数据库连接池 是编写应用服务时经常需要用到的模块,太过频繁地连接数据库对服务性能来说是一个瓶颈,使用缓冲池技术来可以解决。基于java开发的系统中,JDBC是开发人员和数据库使用的常用主要途径,他提供了完备的数据库操作方法接口。考虑到规范的是适用性,JDBC只提供了最直接的数据库操作规范,对数据库资源进行管理,如:对物理连接的管理以及缓冲,由第三方应用服务器来提供。
鉴于此,很多应用系统采用自身编写的数据库连接池来解决数据访问的瓶颈。
在使用java语言进行和数据库有关的应用开发中,一般都使用JDBC来进行和数据库的交互,其中有一个关键概念就是Connection(连接)。它在Java中是一个类,代表一个通道。通过它,应用程序可以从数据库访问数据。
一,下面,讲述如何实现建立数据库连接池。其建立具体步骤如下。
1,建立连接池
首先要建立一个静态的连接池。所谓的静态是指池中的链接是在初始化时就分配好的,并且不能够随意关闭的。
java为用户提供了很多容器类,用户可以方便地构建连接池,如:Vector,Stack等。在系统初始化时,根据配置创建连接并放置在连接池中,以后所使用的连接都是从该连接池中获取,这样就可以避免连接随意建立,关闭造成的开销。
2,分配,释放策略
连接池创建完毕,就可以提供一套自定义的分配,释放策略。
当用户请求数据库连接时,首先看连接池中是否有空闲的连接。如果有空闲的,则把空闲连接分配给用户,并作相应处理,若连接池中没有空闲连接,就在已经分配出去的连接中,寻找一个合适的连接给用户,此时该连接被多个用户使用。
当用户释放数据库连接时,可以根据该连接是否被复用,进行不同处理。如果没有使用者,就被放入到连接池中,而不是关闭。
3,配置策略
用户可以设置数据库连接池中连接的数目。一般的配置策略是:开始时,根据具体的应用需求,给出一个初始的连接池的数目已经连接池可以扩张到的最大连接数目。
4,引用计数
每一个数据库连接,保留一个引用计数,来记录该连接的使用者的个数。在具体的实现上,采用了两级连接池:空闲池和使用池。
空闲池中存放目前没有分配出去的连接;一旦一个连接被分配出去,那么就会放入使用池中,并且增加引用计数。
这样做的有点是:用户可以高效地使用连接,因为一旦空闲池中的连接被全部分配出去,用户就可以根据相应策略从使用池中挑出一个已经正在使用的连接来复用,而不是随意拿出一个连接去复用。策略可以根据需要去选择。
5,事务处理
Connection本身提供了对于事务的支持,可以通过设置Connection的AutoCommit属性为False,显式地调用commit或者rollback方法来实现。但是要安全,高效地进行Connection复用,就必须提供相应的事务支持机制。采用显式的事务支撑方法,每一个事务独占一个连接。这种方法可以大大降低事务处理的复杂性,并且不妨碍连接复用,因为隶属于该事务的所有数据库操作都是通过这个连接完成的,并且事务方法又复用了其他一些数据库方法。
6,封装
普通的数据库方法和事务方法对于连接的使用(分配,释放)是不同的。为了便于使用,对外提供一致的操作接口,对连接进行了封装:即普通连接和事务连接。
7,并发处理
连接管理服务有更大的通用性,必须要考虑到多线程环境,即并发处理。在多线程环境下,必须保证连接管理自身数据的一致性和连接内部数据的一致性,Java提供synchronized关键字来解决并发问题。
二,访问数据库组件
主要有ResultSet,Statement,Connect等
1,Statement
Statement对象用于将SQL语句发送到数据库系统。实际上有3种Statement对象,它们都作为在给定连接上执行SQL语句的容器:Statement,PreparedStatement(它从Statement继承而来)和CallableStatement(它从PreparedStatement继承而来)。
它们都专用于发送特定类型的SQL语句:Statement对象用于执行不带参数的简单SQL语句;
PreparedStatement对象用于执行带或不带IN参数的预编译SQL语句;
CallableStatement对象用于执行对数据库已存储过程的调用。
这里我们只讲述Statement。
(1)创建Statement对象
建立了到特定数据库的连接之后,就可以用该连接发送SQL语句。Statement对象用Connection的方法createStatement创建。
为了执行Statement对象,被发送到数据库的SQL语句将被作为参数提供给Statement的方法:
(2)使用Statement对象执行语句
Statement接口提供了3种执行SQL语句的方法:executeQuery,executeUpdate,execute。
使用哪一个方法由SQL语句所产生的内容决定。
- 方法executeQuery用于产生单个结果集的语句,例如SELECT语句。
- 方法executeUpdate用于执行Insert,Update或Delete语句以及SQL DDL(数据定义语言)语句,例如Create table和Drop table。
Insert,Update或Delete语句的效果是修改表中零行或多行中的一列或多列。
executeUpdate 的返回值是一个整数,指示受影响的行数(即更新的行数)。对于Create table和Drop table等不操作行的语句,executeUpdate 的返回值总是零。
- 方法execute用于执行返回多个结果集,多个更新计数或二者组合的语句。
执行语句的所有方法都将关闭调用的Statement对象的当前打开的结果集。这意味着在重新执行Statement对象之前,需要完成对当前ResultSet对象的处理。
(3)语句完成
当连接处于自动提交模式时,其中所执行的语句完成时将自动提交或还原。语句以及执行且所有结果返回时,即认为已完成。
(4)关闭Statement对象
Statement对象将由Java垃圾回收器自动关闭。而作为一种好的编程风格,应在不需要Statement对象时显式地关闭它们。这将立即释放数据库资源,有助于避免潜在的内存问题。
2,ResultSet
ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些行中数据的访问。ResultSet.next方法用于将光标移动到ResultSet中的下一行,使下一行成为当前行。
ResultSet一般是一个表,其中有查询所返回的列标题及相应的值。
(1)行和光标
ResultSet维护指向其当前数据行的光标。每调用一次next方法,光标向下移动一行。最初它位于第一行之前,因此第一次调用next将把光标置于第一行上,使它成为当前行。
在ResultSet对象或其父Statement对象关闭之前,光标一直保持有效。在SQL中,结果表的光标是有名字的。如果数据库允许定位更新或定位删除,则需要将光标的名字作为参数提供给更新或删除命令。可通过调用方法getCursorName获得光标号。
(2)行
方法getXXX提供了获取当前行中某列值的途径。在每一行内,可按任何次序获取列值。但为了保证可移植性,应该从左至右获取列值,并且一次性地读取列值。
关于ResultSet中列的信息,可通过调用方法ResultSet.getMetaData得到。返回的ResultSetMetaData对象将给出其ResultSet对象各列的编号,类型和属性。如果列名已知,但不知其索引,则可用方法findColumn得到其列号。
(3)数据类型和转换
对于getXXX方法,JDBC驱动程序试图将基本数据转换成指定的Java类型,然后返回适合的Java值。例如:如果getXXX方法为getString,而基本数据库中数据中类型为VARCHAR,则JDBC驱动程序将把VARCHAR转换成Java String。getString的返回值将为java String对象。
(4)Null结果值
要确定给定的结果值是否为Null,必须先读取该列,然后使用ResultSet.wasNull方法检查该次读取是否返回Null。
(5)可选结果集或多结果集
通常使用executeQuery,executeUpdate执行SQL语句。但是有些情况下,用于程序在执行语句之前不知道该语句是否返回结果集。此外存储过程可能返回几个不同的结果集和/或更新计数。
用户不必关闭ResultSet,当产生它的Statement关闭,重新执行或用于从多结果序列中获取下一个结果时,该ResultSet将被Statement自动关闭。