1、数据库连接池的概念
用池来管理Connection,这可以重复使用Connection。有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。池就可以再利用这个Connection对象了。
2.DataSource接口
JDBC提供了javax.sql.DataSource接口,它负责建立与数据库的连接,在应用程序中访问数据库时不必编写连接数据库的代码,可以直接从数据源获得数据库连接
(1)数据库和连接池
在DataSource中事先建立了多个数据库连接,这些数据库连接保存在连接池(ConnectPool)中。java程序访问数据库时,只需要从连接池中取出空闲状态的数据库连接,当程序访问数据库结束,再将数据库连接放回连接池,这样做可以调高访问数据库的效率。
如果Web应用每次接收到客户的请求,都和数控建立一个连接,数控操作结束就断开连接,这样会消费大量的时间和资源。因为数据库每次配置连接都要将Connection对象加载到内存中,再验证用户名和密码。
(2)数据源和JNDI资源
由于DataSource对象是由Tomcat提供的,因此不能够在程序中创建一个DataSource对象,而要采用JNDI技术来获得DataSource对象的引用。 可以简单的把JNDI理解为一种将对象和名字绑定的技术,对象工厂负责生产出对象,这些对象都和唯一的名字绑定,外部程序可以通过名字来获得某个对象的引用。在javax.naming包中提供了Context接口,该接口提供了将对象和名字绑定,以及通过名字检索对象的方法。
3.DBCP数据源
DBCP是Apache提供的一款开源免费的数据库连接池!Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。Hibernate3.0之后不再对DBCP提供支持!因为Hibernate声明DBCP有致命的缺欠!
需要应用程序应在系统中增加如下两个 jar 文件:
·Commons-dbcp.jar:连接池的实现
·Commons-pool.jar:连接池实现的依赖库
实现DBCP
(1)加入jar包
(2)编写dbcpconfig.properties
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/testdb username=root password=123456 #<!-- 初始化连接 --> initialSize=10 #最大连接数量 maxActive=50 #<!-- 最大空闲连接 --> maxIdle=20 #<!-- 最小空闲连接 --> minIdle=5 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。 connectionProperties=useUnicode=true;characterEncoding=UTF8 #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的只读(read-only)状态。 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix) defaultReadOnly=false #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=REPEATABLE_READ
(3)在获取数据库连接的工具类(如jdbcUtils)的静态代码块中创建池
package cn.zy.utils; import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; /* * 数据库连接工具类DBCP */ public class JdbcUtils_DBCP { /* * 在java中,编写数据库连接池需实现java.sql.DataSource接口,每一种数据库连接池都是DataSource接口的实现 * DBCP连接池就是javax.sql.DataSource接口的一个具体实现 */ private static DataSource ds =null; //在静态代码块中创建数据库连接池 static { try { //加载配置文件 InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"); Properties prop = new Properties(); prop.load(in); //创建数据源 ds = BasicDataSourceFactory.createDataSource(prop); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } /* * 从数据源中获取数据库连接 */ public static Connection getConnection() throws SQLException{ return ds.getConnection(); } /* * 释放资源 */ public static void release(Connection conn,Statement st,ResultSet rs){ if(rs!=null){ try{ rs.close(); }catch (Exception e){ e.printStackTrace(); } if(st!=null){ try { st.close(); } catch (Exception e) { e.printStackTrace(); } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } } }
测试连接
package cn.zy.test; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import org.junit.Test; import cn.zy.utils.JdbcUtils_DBCP; /* * 测试DBCP数据源 */ public class DbcpTest { @Test public void dbcpDataSourceTest(){ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try { //获取数据库连接 conn = JdbcUtils_DBCP.getConnection(); String sql = "insert into account(name,money) values(?,?)"; st = conn.prepareStatement(sql); st.setString(1, "D"); st.setFloat(2, 2000); st.executeUpdate(); } catch (Exception e) { e.printStackTrace(); }finally{ //释放资源 JdbcUtils_DBCP.release(conn, st, rs); } } }
4.C3P0数据源
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。C3P0数据源在项目开发中使用得比较多。
c3p0与dbcp区别:
·dbcp没有自动回收空闲连接的功能
·c3p0有自动回收空闲连接功能
在应用程序中加入C3P0连接池
(1)导入相关jar包
c3p0-0.9.2-pre1.jar、mchange-commons-0.2.jar,如果操作的是Oracle数据库,那么还需要导入c3p0-oracle-thin-extras-0.9.2-pre1.jar
(2)在src下加入C3P0的配置文件:c3p0-config.xml,注意:
配置文件要求:
l 文件名称:必须叫c3p0-config.xml
l 文件位置:必须在src下
c3p0-config.xml的配置信息如下:
<?xml version="1.0" encoding="UTF-8"?> <!-- c3p0-config.xml必须位于类路径下面 private static ComboPooledDataSource ds; static{ try { ds = new ComboPooledDataSource("MySQL"); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } --> <c3p0-config> <!-- C3P0的缺省(默认)配置, 如果在代码中“ComboPooledDataSource ds = new ComboPooledDataSource();”这样写就表示使用的是C3P0的缺省(默认)配置信息来创建数据源 --> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/testdb</property> <property name="user">root</property> <property name="password">123456</property> <property name="acquireIncrement">5</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">5</property> <property name="maxPoolSize">20</property> </default-config> <!-- C3P0的命名配置, 如果在代码中“ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");”这样写就表示使用的是name是MySQL的配置信息来创建数据源 --> <named-config name="MySQL"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/testdb</property> <property name="user">root</property> <property name="password">123456</property> <property name="acquireIncrement">5</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">5</property> <property name="maxPoolSize">20</property> </named-config> </c3p0-config>
(3)在获取数据库连接的工具类(如jdbcUtils)的静态代码块中创建池
package cn.zy.utils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; /* * 数据库连接工具类 */ public class JdbcUtils_C3P0 { private static ComboPooledDataSource dataSource = null; //在静态块中创建数据库连接池 static{ try { //通过代码创建数据库连接池 /*ds = new ComboPooledDataSource(); ds.setDriverClass("com.mysql.jdbc.Driver"); ds.setJdbcUrl("jdbc:mysql://localhost:3306/testdb"); ds.setUser("root"); ds.setPassword("123456"); ds.setInitialPoolSize(10); ds.setMinPoolSize(5); ds.setMinPoolSize(20);*/ //通过读取xml来获取数据源 //ds = new ComboPooledDataSource();//使用C3P0的默认配置来创建数据源 dataSource = new ComboPooledDataSource("MySQL");//使用C3P0的命名配置来创建数据源 } catch (Exception e) { throw new ExceptionInInitializerError(e); } } /* * 从数据源中获取数据库连接 */ public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } /* * 返回连接池 */ public static DataSource getDataSource() { return dataSource; } /* * 释放资源 */ public static void release(Connection conn,Statement st,ResultSet rs){ if(rs!=null){ try{ //关闭存储查询结果的ResultSet对象 rs.close(); }catch (Exception e) { e.printStackTrace(); } rs = null; } if(st!=null){ try{ //关闭负责执行SQL命令的Statement对象 st.close(); }catch (Exception e) { e.printStackTrace(); } } if(conn!=null){ try{ //将Connection连接对象还给数据库连接池 conn.close(); }catch (Exception e) { e.printStackTrace(); } } } }
编写测试类:
package cn.zy.test; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import org.junit.Test; import cn.zy.utils.JdbcUtils_C3P0; public class C3p0Test { @Test public void fun(){ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try { conn = JdbcUtils_C3P0.getConnection(); String sql = "insert into account(name,money) values(?,?)"; st = conn.prepareStatement(sql); st.setString(1, "F"); st.setFloat(2,3000); st.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } } }
二、DBUtils工具
1.DBUtils工具介绍
DButils是JDBC的简化开发工具包。需要导入commons-dbutils-1.6.jar才能够正常使用DButils工具类
DButils封装了对JDBC的操作,简化了JDBC操作,可以少些代码。DButils的三个核心功能:
·QueryRunner提供了对sql语句操作的API
·ResultSetHandler接口,用于定义select操作后怎样去封装结果
· DButils类,是一个工具类,定义了关闭资源与事物处理的方法
2.QueryRunner类
(1)query(Connection conn,String sql,ResultSetHandler rsh,Object…params),用来完成表数据的查询操作。
esultSetHandler结果集处理类
(2)update(Connection conn,String sql,Object…params),用于完成表数据增加、删除、修改的操作
3、ResultSetHandler接口
该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式。
ResultSetHandler接口提供了一个单独的方法:Object handle(java.sql.ResultSet.rs)。
4.ResultSetHandler实现类
ArrayHandler:把结果集中的第一行数据转换成对象数组。 ArrayListHandler:把结果集中的每一行数据都转换成一个对象数组,再存放到List中。 BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。 BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。 MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。 MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List。 ColumnListHandler:将结果集中某一列的数据存放到List中。 KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里(List),再把这些map再存到一个map里,其key为指定的列。 ScalarHandler:获取结果集中第一行数据指定列的值,常用来进行单值查询