C3P0和spring dbcp差不多,是一个连接池解决方案,其相比dbpc多出的一个功能是能够通过配置使超时不用的连接释放。C3P0中主要使用的是ComboPooledDataSource类,用其getConnection方法来得到java.sql.Connection,此时的connectin调用close方法并不会关闭连接,而是返回到连接池。可以通过ComboPooledDataSource的getNumConnections方法来查看close前后的连接数目来证实。
spring整合C3P0的主要配置参数如下
<!-- c3p0连接池配置 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="wemedia"/>
<property name="password" value="qzGD+eAI8Hr6dHM"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://wemedia.db.spaces.sohu.com:3306/wemedia?useUnicode=true&characterEncoding=UTF-8"/>
<!--连接池中保留的最大连接数。默认值: 15 -->
<property name="maxPoolSize" value="20"/>
<!-- 连接池中保留的最小连接数,默认为:3-->
<property name="minPoolSize" value="5"/>
<!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3-->
<property name="initialPoolSize" value="10"/>
<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->
<property name="maxIdleTime" value="120"/>
<!-- 当连接池连接耗尽时,客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒。默认: 0 -->
<property name="checkoutTimeout" value="5000"/>
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 -->
<property name="acquireIncrement" value="2"/>
<!--定义在从数据库获取新连接失败后重复尝试的次数。默认值: 30 ;小于等于0表示无限次-->
<property name="acquireRetryAttempts" value="10"/>
<!--重新尝试的时间间隔,默认为:1000毫秒-->
<property name="acquireRetryDelay" value="1000" />
<!--每60秒检查所有连接池中的空闲连接。默认值: 0,不检查 -->
<property name="idleConnectionTestPeriod" value="60"/>
</bean>
需要说明下initialPoolSize参数是在第一次建立连接的时候,会产生initialPoolSize个连接,并不是初始化的时候。
如果不用dbutils来结合的话,就像使用jdbc那样用即可了。但是需要编码来管理连接的创建和释放,这部分和sql语句结果集的处理(比如封装成bean),Apache的dbutils又做得比较好,所以想到了将两者结合使用。
package com.sohu.wemedia.space.util;
import java.sql.Connection;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* C3P0连接池的工具类,借助apache.commons.dbutils
*
* @author ranjiehu
*
*/
public class C3P0Util {
/**
* 返回Object数组,需要自己转换类型
*
* @param sql
* @param dataSource
* @param resultSetHandler
* @return
*/
public static Object[] getByArrayHandler(String sql,
ComboPooledDataSource dataSource, ArrayHandler arrayHandler) {
Connection connection = null;
QueryRunner queryRunner = new QueryRunner();
try {
connection = dataSource.getConnection();
Object[] rs = queryRunner.query(connection, sql, arrayHandler);
return rs;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
connection.close();// 返回资源到连接池,假close
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 返回泛型对象,根据ResultSetHandler来转换
*
* @param sql
* @param dataSource
* @param resultSetHandler
* @return
*/
public static <T> T getByResultSetHandler(String sql,
ComboPooledDataSource dataSource,
ResultSetHandler<T> resultSetHandler) {
Connection connection = null;
QueryRunner queryRunner = new QueryRunner();
try {
connection = dataSource.getConnection();
T rs = (T) queryRunner.query(connection, sql, resultSetHandler);
return rs;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
connection.close();// 返回资源到连接池,假close
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
向上暴露数据源、sql、以及各种处理方法(各种ResultSetHandler及其子集),使用时将Spring中配置的ComboPooledDataSource代表的数据源传入即可。
比如将查询结果转为对象的list,如下:
List<WeekRank> list = C3P0Util.getByResultSetHandler(sql,
dataSource, new ResultSetHandler<List<WeekRank>>() {
@Override
public List<WeekRank> handle(ResultSet paramResultSet)
throws SQLException {
List<WeekRank> list = new ArrayList<WeekRank>();
int i = 1;
while (paramResultSet.next()) {
WeekRank weekRank = new WeekRank();
weekRank.setRank(i++);
weekRank.setUserId(paramResultSet
.getLong("user_id"));
weekRank.setPlayCount(paramResultSet
.getLong("play_count"));
list.add(weekRank);
}
return list;
}
});