已阅读5页,还剩11页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Java高级编程与应用开发之数据库编程综述赵灯1. JDBC概念1.1. 什么是JDBCJava数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,可以为多种关系数据库提供统一访问。1.2. JDBC特点和开放式数据库互连(Open Database Connectivity,简称ODBC)不同,ODBC是Microsoft公司提供的用于访问数据库的应用程序接口,ODBC虽然可以在任意一计算机语言中使用,但仅限于Windows平台,JDBC秉承了Java的跨平台的特性,虽然它只能在Java语言中使用。2. JDBC的体系结构. JDBC组成JDBC包含5部分:1. JDBC Application:负责程序和用户之间的交互;2. JDBC API:这是为程序员准备的面向应用程序的编程接口;3. JDBC Driver Manager:JDBC驱动程序管理器为应用程序加载和调用驱动程序;4. JDBC Driver API:为各个商业数据库厂商提供的编程接口;5. Data Source:各数据库厂商的数据库系统;JDBC至数据库的通信路径如下所示:图表 1Java程序首先使用JDBC API来与JDBC Driver Manager交互,由JDBC Driver Manager载入指定的JDBC drivers, 或者通过JDBC/ODBC桥的方式和数据库取得联系,以后就可以通过JDBC API来存取数据库。2.2. JDBC API和JDBC Driver API简介如图表1所示,Sun公司制定了两套接口,JDBC API和JDBC驱动API,现就两套API介绍如下。..1. JDBC API JDBC API主要位于JDK中的java.sql包中(之后扩展的内容位于javax.sql包中),主要包括(斜体代表接口,需驱动程序提供者来具体实现):l DriverManager:负责加载各种不同驱动程序(Driver),并根据不同的请求,向调用者返回相应的数据库连接(Connection)。 l Driver:驱动程序,会将自身加载到DriverManager中去,并处理相应的请求并返回相应的数据库连接(Connection)。 l Connection:数据库连接,负责与进行数据库间通讯,SQL执行以及事务处理都是在某个特定Connection环境中进行的。可以产生用以执行SQL的Statement。 l Statement:用以执行SQL查询和更新(针对静态SQL语句和单次执行)。 l PreparedStatement:用以执行包含动态参数的SQL查询和更新(在服务器端编译,允许重复执行以提高效率)。 l CallableStatement:用以调用数据库中的存储过程。 l SQLException:代表在数据库连接的建立和关闭和SQL语句的执行过程中发生了例外情况(即错误)。2.2.2. JDBC Driver APIJDBC驱动程序共分四种类型:1. JDBC-ODBC桥这种类型的驱动把所有JDBC的调用传递给ODBC,再让后者调用数据库本地驱动代码(也就是数据库厂商提供的数据库操作二进制代码库,例如Oracle中的oci.dll)。优点:只要有对应的ODBC驱动(大部分数据库厂商都会提供),几乎可以访问所有的数据库。 缺点:执行效率比较低,不适合大数据量访问的应用; 由于需要客户端预装对应的ODBC驱动,不适合Internet/Intranet应用。 2. 本地API驱动这种类型的驱动通过客户端加载数据库厂商提供的本地代码库(CC+等)来访问数据库,而在驱动程序中则包含了Java代码。优点:速度快于第一类驱动(但仍比不上第3、第4类驱动)。 缺点:由于需要客户端预装对应的数据库厂商代码库,仍不适合Internet/Intranet应用。3. 网络协议驱动这种类型的驱动给客户端提供了一个网络API,客户端上的JDBC驱动程序使用套接字(Socket)来调用服务器上的中间件程序,后者在将其请求转化为所需的具体API调用。优点:不需要在客户端加载数据库厂商提供的代码库,单个驱动程序可以对多个数据库进行访问,可扩展性较好。 缺点:在中间件层仍需对最终数据进行配置; 由于多出一个中间件层,速度不如第四类驱动程序。 4. 本地协议驱动这种类型的驱动使用Socket,直接在客户端和数据库间通信。优点:访问速度最快; 这是最直接、最纯粹的Java实现。 缺点:因为缺乏足够的文档和技术支持,几乎只有数据库厂商自己才能提供这种类型的JDBC驱动; 需要针对不同的数据库使用不同的驱动程序。3. JDBC应用程序开发现将JDBC应用程序开发的整个过程详解如下:3.3.1. 配置驱动程序1. 使用JDBC-ODBC桥驱动,需要配置ODBC数据源;2. 使用纯Java驱动,需要引用驱动程序包,可以在各大数据库厂商的官方网站上下载。而在不同的IDE下,有不同的配置方法,这里不做说明,可自行查阅;.2. 开发步骤1. 使用import导入程序编写过程中用到的类:DriverManager、Connection、Statement、ResultSet2. 利用Class.forName()方法来加载JDBC驱动程序(Driver)至DriverManager:Class.forName(“驱动程序的类名”);使用不同的连接方式或者数据源,所采用的驱动程序类都不一样,请根据实际情况填写。如:JDBC-ODBC桥驱动类:sun.jdbc.odbc.JdbcOdbcDriver纯Java驱动类(SQLServer 2000):com.microsoft.jdbc.sqlserver.SQLServerDriver3. 然后,从DriverManager中,通过JDBC URL,用户名,密码来获取相应的数据库连接(Connection):Connection conn = DriverManager.getConnection( jdbc:somejdbcvendor:other data needed by some jdbc vendor, / URL myLogin, / 用户名 myPassword ); / 密码创建一个Connection对象URL:连接数据库服务器的地址,不同的驱动,url的内容不一样。JDBC-ODBC桥驱动类的url:jdbc:odbc:数据源的名字(在使用JDBC-ODBC桥驱动之前创建);纯Java驱动类的URL:jdbc:数据库厂家规定的格式:例如,连接Sql Server数据库的URL为:jdbc:microsoft:sqlserver:/数据库地址:1433;databaseName=数据库名字;4. 创建一个Statement(或者PreparedStatement或者CallableStatement)对象Statement stmt=con.createStatement();或者PreparedStatement stmt=con.prepareStatement(Sql语句);CallableStatement stmt=con.prepareCall(Sql语句)5. 执行sql语句int i =Stmt.excuteUpdate(sql语句);或ResultSet rs=stmt.excuteQuery(sql语句)6. 处理ResultSetWhile(Boolean next():下移一行)取得字段的值:getXXX(字段的索引或者名字)7. 关闭ResultSet对象、Statement对象、Connection对象Rs.close();Stmt.close();Con.close();import java.sql.*;/导入public class MyJDBC public static void main(String args) /加载并注册驱动try Class.forName(com.microsoft.jdbc.sqlserver.SQLServerDriver); catch (ClassNotFoundException e) e.printStackTrace();try /URLString url = jdbc:microsoft:sqlserver:/localhost:1433;databaseName=stuDB;/创建一个Connection对象Connection con = DriverManager.getConnection(url,sa,);/创建一个Statement对象;Statement stmt = con.createStatement();/执行DML语句做更新操作,或者执行SELECT语句获取结果集/String sql = update authors_bak set au_lname = aaa where au_id = 172-32-1176;String sql = exec proc_test;if (stmt.execute(sql)System.out.println(结果如下:);ResultSet rs = stmt.getResultSet();while (rs.next()System.out.println(rs.getString(stuName);elseSystem.out.println(更新操作!);/stmt.execute(update authors_bak set au_lname = deng where au_id = 172-32-1176);stmt.close();con.close(); catch (SQLException e) / TODO Auto-generated catch blocke.printStackTrace();3.3. 预编译通常,Java程序员们更倾向于使用PreparedStatement。下面的例子使用上例中的conn对象: PreparedStatement ps = null; ResultSet rs = null; try ps = conn.prepareStatement( SELECT i.*, j.* FROM Omega i, Zappa j WHERE i = ? AND j = ? ); / 使用问号作为参数的标示 / 进行参数设置 / 与大部分Java API中下标的使用方法不同,字段的下标从1开始,1代表第一个问号 / 当然,还有其他很多针对不同类型的类似的PreparedStatement.setXXX()方法 ps.setString(1, Poor Yorick); ps.setInt(2, 8008);import java.sql.*;public class StuTest /获得连接的方法public static Connection getConnection()Connection con = null;String url = jdbc:microsoft:sqlserver:/localhost:1433;databaseName=Stu;try Class.forName(com.microsoft.jdbc.sqlserver.SQLServerDriver);con = DriverManager.getConnection(url, sa, ); /获得一个新的连接if (con != null)System.out.println(连接成功!); catch (ClassNotFoundException e) e.printStackTrace(); catch (SQLException e) e.printStackTrace();return con;/关闭连接public static void closeConnection(ResultSet rs, Statement stmt, Connection con)try if (rs != null)rs.close();if (stmt != null)stmt.close();if (con != null)con.close(); catch (SQLException e) e.printStackTrace();/增加学员信息public staticvoid insertStudent()Connection conn = null;Statement stmt = null;ResultSet rs = null;String sql = insert into student values(95001, 张三, 20, 男);int rowcount = 0;try conn = getConnection();stmt = conn.createStatement();rowcount = stmt.executeUpdate(sql);System.out.println(加入了+rowcount+行数据!); catch (SQLException e) e.printStackTrace();finallycloseConnection(rs, stmt, conn);/更新数据public staticvoid updateStudent()Connection conn = null;Statement stmt = null;ResultSet rs = null;String sql = update student set sname = 李四 where sno = 95001;int rowcount = 0;try conn = getConnection();stmt = conn.createStatement();rowcount = stmt.executeUpdate(sql);System.out.println(更新了+rowcount+行数据!); catch (SQLException e) e.printStackTrace();finallycloseConnection(rs, stmt, conn);/带参数的更新操作public static void updateStudentName(String sno, String sname)Connection conn = null;PreparedStatement pstmt = null;ResultSet rs = null;String sql = update student set sname = ? where sno = ?;try conn = getConnection();pstmt = conn.prepareStatement(sql);pstmt.setString(1, sname);pstmt.setString(2, sno);pstmt.executeUpdate(); catch (SQLException e) e.printStackTrace();finallycloseConnection(rs, pstmt, conn);public staticvoid insertStudent(String sno, String sname, int sage, String ssex)Connection conn = null;PreparedStatement pstmt = null;ResultSet rs = null;String sql = insert into student values(?,?,?,?);int rowcount = 0;try conn = getConnection();pstmt = conn.prepareStatement(sql);pstmt.setString(1, sno);pstmt.setString(2, sname);pstmt.setInt(3, sage);pstmt.setString(4, ssex);rowcount = pstmt.executeUpdate();System.out.println(插入了+rowcount +行数据 ); catch (SQLException e) e.printStackTrace();finallycloseConnection(rs, pstmt, conn);public static Student selectStudentByID(String sno)Connection conn = null;PreparedStatement pstmt = null;ResultSet rs = null;String sql =select * from student where sno=?;Student s = new Student();try conn=getConnection();pstmt=conn.prepareStatement(sql);pstmt.setString(1, sno);rs=pstmt.executeQuery();while(rs.next()s.sNo = rs.getString(1);s.sName = rs.getString(2);s.sAge = rs.getInt(3);s.sSex = rs.getString(4); catch (SQLException e) / TODO Auto-generated catch blocke.printStackTrace();finallycloseConnection(rs, pstmt, conn);return s;public static void main(String args) Connection con = null;Statement stmt = null;ResultSet rs = null;boolean 得到结果集 = false;/String sql = select * from student;String sql = update student set sname = abcdef;try con = getConnection();stmt = con.createStatement();得到结果集 = stmt.execute(sql);/返回一个布尔类型,如果执行的是select语句,返回真,否则为假if (得到结果集)/将结果集存入rs;rs = stmt.getResultSet();/输出while(rs.next()System.out.println(rs.getString(2);elseSystem.out.println(更新了数据); catch (SQLException e) / TODO Auto-generated catch blocke.printStackTrace();finallycloseConnection(rs, stmt, con);3.4. Java调用存储过程:public static void execProc()Connection con = null;CallableStatement cstmt = null;ResultSet rs = null;try con = getConnection();cstmt = con.prepareCall(?=call proc_test001(?, default, ?);cstmt.registerOutParameter(1, Types.INTEGER);cstmt.registerOutParameter(2, Types.VARCHAR);cstmt.setString(3, abcdefg);if (cstmt.execute()rs = cstmt.getResultSet();while (rs.next()System.out.print(rs.getString(1) + t);System.out.println(rs.getString(2) + t);System.out.println(cstmt.getInt(1);System.out.println(cstmt.getString(2); catch (Exception e) e.printStackTrace();finallycloseConnetion(rs, cstmt, con);3.5. 连接池3.5.1. 连接池原理连接池技术的核心思想是:连接复用,通过建立一个数据库连接池以及一套连接使用、分配、管理策略,使得该连接池中的连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。另外,由于对JDBC中的原始连接进行了封装,从而方便了数据库应用对于连接的使用(特别是对于事务处理),提高了开发效率,也正是因为这个封装层的存在,隔离了应用的本身的处理逻辑和具体数据库访问逻辑,使应用本身的复用成为可能。3.5.2. 连接池的建立应用程序中建立的连接池其实是一个静态的。所谓静态连接池是指连接池中的连接在系统初始化时就已分配好,且不能随意关闭连接。Java中提供了很多容器类可以方便的构建连接池,如:Vector、Stack、Servlet、Bean等,通过读取连接属性文件Cperties与数据库实例建立连接。在系统初始化时,根据相应的配置创建连接并放置在连接池中,以便需要使用时能从连接池中获取,这样就可以避免连接随意的建立、关闭造成的开销。3.5.3. 连接池的管理连接池管理策略是连接池机制的核心。当连接池建立后,如何对连接池中的连接进行管理,解决好连接池内连接的分配和释放,对系统的性能有很大的影响。连接的合理分配、释放可提高连接的复用,降低了系统建立新连接的开销,同时也加速了用户的访问速度。下面介绍连接池中连接的分配、释放策略。连接池的分配、释放策略对于有效复用连接非常重要,我们采用的方法是一个很有名的设计模式:Reference Counting(引用记数)。该模式在复用资源方面应用的非常广泛,把该方法运用到对于连接的分配释放上,为每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数。具体的实现方法是:当客户请求数据库连接时,首先查看连接池中是否有空闲连接(指当前没有分配出去的连接)。如果存在空闲连接,则把连接分配给客户并作相应处理(即标记该连接为正在使用,引用计数加1)。如果没有空闲连接,则查看当前所开的连接数是不是已经达到maxConn(最大连接数),如果没达到就重新创建一个连接给请求的客户;如果达到就按设定的maxWaitTime(最大等待时间)进行等待,如果等待maxWaitTime后仍没有空闲连接,就抛出无空闲连接的异常给用户。当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就删除该连接,并判断当前连接池内总的连接数是否小于minConn(最小连接数),若小于就将连接池充满;如果没超过就将该连接标记为开放状态,可供再次复用。可以看出正是这套策略保证了数据库连接的有效复用,避免频繁地建立、释放连接所带来的系统资源开销。3.5.4. 连接池的关闭当应用程序退出时,应关闭连接池,此时应把在连接池建立时向数据库申请的连接对象统一归还给数据库(即关闭所有数据库连接),这与连接池的建立正好是一个相反过程。3.5.5. 连接池的配置数据库连接池中到底要放置多少个连接,才能使系统的性能更佳,用minConn和maxConn来限制。minConn是当应用启动的时候连接池所创建的连接数,如果过大启动将变慢,但是启动后响应更快;如果过小启动加快,但是最初使用的用户将因为连接池中没有足够的连接不可避免的延缓了执行速度。因此应该在开发的过程中设定较小minConn,而在实际应用的中设定较大minConn。maxConn是连接池中的最大连接数,可以通过反复试验来确定此饱和点。为此在连接池类ConnectionPool中加入两个方法getActiveSize()和getOpenSize(),ActiveSize 表示某一时间有多少连接正被使用,OpenSize表示连接池中有多少连接被打开,反映了连接池使用的峰值。将这两个值在日志信息中反应出来, minConn的值应该小于平均ActiveSize,而maxConn的值应该在activeSize和OpenSize之间。3.5.6. 事务处理前面讨论的是关于使用数据库连接进行普通的数据库访问。对于事务处理,情况就变得比较复杂。因为事务本身要求原则性的保证,此时就要求对于数据库的操作符合All-All-Nothing原则,即要么全部完成,要么什么都不做。如果简单的采用上述的连接复用的策略,就会发生问题,因为没有办法控制属于同一个事务的多个数据库操作方法的动作,可能这些数据库操作是在多个连接上进行的,并且这些连接可能被其他非事务方法复用。Connection本身具有提供了对于事务的支持,可以通过设置Connection的AutoCommit属性为false,显式的调用 commit或rollback方法来实现。但是要安全、高效的进行连接复用,就必须提供相应的事务支持机制。方法是:采用显式的事务支撑方法,每一个事务独占一个连接。这种方法可以大大降低对于事务处理的复杂性,并且又不会妨碍连接的复用。连接管理服务提供了显式的事务开始、结束(commit或rollback)声明,以及一个事务注册表,用于登记事务发起者和事务使用的连接的对应关系,通过该表,使用事务的部分和连接管理部分就隔离开,因为该表是在运行时根据实际的调用情况动态生成的。事务使用的连接在该事务运行中不能被复用。在实现中,用户标识是通过使用者所在的线程来标识的。后面的所有对于数据库的访问都是通过查找该注册表,使用已经分配的连接来完成的。当事务结束时,从注册表中删除相应表项。3.5.7. 封装从上面的论述可以看出,普通的数据库方法和事务方法对于连接的使用(分配、释放)是不同的,为了便于使用,对外提供一致的操作接口,我们对连接进行了封装:普通连接和事务连接,并利用了Java中的强大的面向对象特性:多态。普通连接和事务连接均实现了一个DbConnection接口,对于接口中定义的方法,分别根据自己的特点作了不同的实现,这样在对于连接的处理上就非常的一致了。3.5.8. 并发为了使连接管理服务有更大的通用性,我们必须要考虑到多线程环境,即并发问题。在一个多线程的环境下,必须要保证连接管理自身数据的一致性和连接内部数据的一致性,在这方面Java提供很好的支持(synchronized关键字),这样就很容易使连接管理成为线程安全的。3.5.9. 多数据库服务器在实际应用中,应用程序常常需要访问多个不同的数据库。如何通过同一个连接池访问不同的数据库,是应用程序需要解决的一个核心问题。下面介绍一种解决的途径:首先,定义一个数据库连接池参数的类,定义了数据库的JDBC驱动程序类名,连接的URL以及用户名口令等等一些信息,该类是用于初始化连接池的参数:public class ConnectionParam implements Serializable/各初始化参数的定义 其次是连接池的工厂类ConnectionFactory,通过该类将一个连接池对象与一个名称对应起来,使用者通过该名称就可以获取指定的连接池对象,实现的主要代码如下:public class ConnectionFactorystatic Hashtable connectionPools = /用来保存数据源名和连接池对象的关系public static DataSource lookup(String dataSourceName) throwsNameNotFoundException/查找名字为dataSourceName的数据源public static DataSource bind(String name, ConnectionParam param)throws Exception/将名字name与使用param初始化的连接池对象绑定public static void unbind(String name) throws NameNotFoundException/将与名字name绑定的连接池对象删除 连接池应用的实现一个完整的连接池应用包括三个部分:DBConnectionPool类,负责从连接池获取(或创建)连接、将连接返回给连接池、系统关闭时关闭所有连接释放所有资源;DBConnectionManager类,负责装载和注册JDBC驱动、根据属性文件中定义的属性创建DBConnectionPool、跟踪应用程序对连接池的引用等;应用程序对连接池的使用。本文实现的数据库连接池包括一个管理类DBConnectionManager,负责提供与多个连接池对象(DBConnectionPool类)之间的接口。每一个连接池对象管理一组封装过的JDBC连接对象Conn,封装过的JDBC连接对象Conn可以被任意数量的Model层的组件共享。类Conn 的设计很简单,如下所示:Class Co
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 巴中橡胶跑道施工方案(3篇)
- 东莞夜场营销方案(3篇)
- 乐队露营活动策划方案(3篇)
- 娄底餐饮活动策划方案(3篇)
- 线下换装活动策划方案(3篇)
- 2025年中石油招聘考试试卷真题
- 浙江省妇女干部学校招聘考试真题2025
- 2025年莱阳市高校毕业生三支一扶考试真题《综合知识》
- 2025临沂市沂南县界湖街道社区工作者招聘考试真题及答案
- 无人机电子技术基础课件 8.2 加法器
- 网络综合布线进线间子系统概述
- 耳穴压豆完整版本
- 2024贵州贵阳中考物理试题及答案 2024年中考物理试卷
- 特发性肺纤维化急性加重AEIPF诊治指南
- DB11-T 1938-2021 引调水隧洞监测技术导则
- WB/T 1045-2012驶入式货架
- GB/T 4295-2019碳化钨粉
- 文化管理学自考复习资料自考
- 三年级下册《对鲜花》音乐教案冯雨婷
- 使用拐杖操作流程及评分标准
- 基金会财务报表审计指引
评论
0/150
提交评论