一、数据库连接池
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:获取结果集中第一行数据指定列的值,常用来进行单值查询