前言
-
一般我们在项目中操作数据库时,都是每次需要操作数据库就建立一个连接,操作完成后释放连接。因为jdbc没有保持连接的能力,一旦超过一定时间没有使用(大约几百毫秒),连接就会被自动释放掉。而每次新建连接都需要140毫秒左右的时间,所以耗费时间比较多。若使用C3P0连接池来池化连接,随时取用,则平均每次取用只需要10-20毫秒。这在高并发随机访问数据库的时候对效率的提升有很大帮助。
-
C3P0连接池会根据你的配置来初始化N个数据库连接,空闲T时间后连接过期又会自动新建K个连接使得连接池总有空闲的数据库连接等待被取用。我们只需通过dataSourse.getConnection()即可从线程池中取用一个已经连接好的空闲连接,执行数据库操作。然后“断开”(放回)这个连接,把这个连接的使用权放回连接池。真正的数据库连接的创建与释放是由C3P0在后台自动完成的,我们花的只是取用与释放占用权的时间。全程耗时10+毫秒,比原来提高了几十倍。
常见的连接池
DBCP连接池、C3P0连接池
-
Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!
注: -
驱动是由数据库厂商提供,是对Java的JDBC接口的实现
连接池不是数据库厂商提供的,如DBCP是Apache提供的,C3P0连接池则是开源项目,要求各个厂商必须实现Java提供的BasicDataSource接口来对接各类连接池。
连接池实现 注册驱动 和 获取连接 两部分功能。
C3P0连接池
使用流程:
public void demo2() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//1、创建连接池,默认去类路径下查找c3p0-config.xml配置文件
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2、从连接池中获取连接
conn = dataSource.getConnection();
//3、编写SQL
String sql = "select * from account";
//4、预编译SQL(防止SQL注入,执行效率高)
pstmt = conn.prepareStatement(sql);
//5、执行SQL
rs = pstmt.executeQuery();
//6、遍历并打印输出
while(rs.next()) {
System.out.println(rs.getInt("id") +" "+rs.getString("name") +" "+rs.getString("money"));
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(rs, pstmt, conn);
}
}
1、添加jar包:
c3p0-0.9.1.2.jar
mysql-connector-java-5.1.30.jar
c3p0下载地址
2、编写配置文件c3p0-config.xml 放在src中
使用c3p0时,会自动识别并加载c3p0-config.xml文件,所以,这个文件的名字不能随意修改。
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///web_test</property>
<property name="user">root</property>
<property name="password">123456</property>
<!-- 初始化为5个连接 -->
<property name="initialPoolSize">5</property>
<!-- 最小连接数 -->
<property name="minPoolSize">5</property>
<!-- 最大连接数 -->
<property name="maxPoolSize">20</property>
</default-config>
</c3p0-config>
3、编写工具类:C3P0Utils.java
/**
* c3p0版本
* JDBC的工具类
* @author wanzhaocheng
*/
public class JDBCUtils2 {
//创建一个c3p0连接池:但是这个连接池只需要创建一次即可
private static final ComboPooledDataSource dataSource = new ComboPooledDataSource();
/**
* 获得连接的方法
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
/**
* 获得连接池
*/
public static DataSource getDataSource() {
return dataSource;
}
/**
* 释放资源的方法
* @return
*/
public static void release(Statement stmt,Connection conn) {
//释放资源
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
public static void release(ResultSet rs, Statement stmt,Connection conn) {
//释放资源
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
4、使用c3p0的测试范例
/**
* 工具类的测试
* @author wanzhaocheng
*
*/
public class C3P0Demo2 {
@Test
/**
* 使用自定义工具类的测试
*/
public void demo2() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//获得连接:从工具类中获取
conn = JDBCUtils2.getConnection();
//编写SQL
String sql = "select * from account";
//预编译SQL
pstmt = conn.prepareStatement(sql);
//执行SQL
rs = pstmt.executeQuery();
while(rs.next()) {
System.out.println(rs.getInt("id") +" "+rs.getString("name") +" "+rs.getString("money"));
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(rs, pstmt, conn);
}
}
}