c3p0源码分析v1
版本:0.9.1.2
数据源
入口类: ComboPooledDataSource
getConnection方法在AbstractPoolBackedDataSource类中实现。
获取连接
触发机制:
应用主动调用。
调用过程:
1、AbstractPoolBackedDataSource类getConnection方法
public Connection getConnection()
throws SQLException
{
PooledConnection pc = getPoolManager().getPool ().checkoutPooledConnection();
return pc.getConnection();
}
接是newProxyConnection,不是物理连接得到连。
说明:
l PooledConnection
包名是javax.sql,是sun针对连接池的接口,它本身包含connection,和这个connection相关的所有statement,result,一个checkout的connection
所做的所有数据库操作,都被pooledconnection所管理。
c3p0默认的实现是NewPooledConnection
l Connection,Statement,Result
操作数据库相关接口,在c3p0中对应于NewProxyConnection,NewProxyStatement,NewProxyResultSet,这些东西统一被PooledConnection管理。
2、C3P0PooledConnectionPool类
public PooledConnection checkoutPooledConnection()
return ((PooledConnection)this.rp.checkoutResource(this.checkoutTimeout));
3、 BasicResourcePool类
public Object checkoutResource(long timeout)
1) 关键步骤代码:Object resc = prelimCheckoutResource(timeout);
查看池中是否有未使用的connection,有就返回(还要判断是否空闲、是否过期);没有,如果没有达到最大数,就生成一个,或者就等待。
2) 关键步骤代码:
boolean refurb = attemptRefurbishResourceOnCheckout (resc);
得到连接后,检测连接的可用性。
3) 连接可用,接着判断连接是否处于管理中,不在就再调用本方法获取一个,在就返回本连接。
添加连接
触发机制:
获取连接时,BasicResourcePool类prelimCheckoutResource方法调用。
调用过程:
1、 BasicResourcePool类prelimCheckoutResource方法当可用连接数为0时调用recheckResizePool方法。
2、 _recheckResizePool方法判断需要扩容则调用expandPool方法
3、 expandPool方法使用线程池调用AcquireTask(实现Runnable接口)任务进行扩容。
4、 AcquireTask调用mgr.acquireResource[55] 方法获取连接,如果连接池里的连接未到最大数量将获取的连接加入管理和未使用的list中,否则销毁连接。
关闭(回收)连接
触发机制:
应用程序调用连接的close方法。
调用过程:
1、C3P0PooledConnectionPool类里的ConnectionEventListenerImpl监听器类的connectionClosed方法被触发。
2、判断同步还是异步(默认是同步)。异步就采用线程池来处理回收,同步就直接调用BasicResourcePool类的checkinResource方法对连接进行回收,注意是回收不是关闭物理连接。
死锁
C3p0很多操作都是多线程来处理的(如:添加连接,回收连接等),所以进行必要的死锁检测。
由ThreadPoolAsynchronousRunner类的子类DeadlockDetector来执行具体的操作。
DeadlockDetector类继承了TimerTask,由Timer来调度DeadlockDetecto运行。
DeadlockDetector类有2个属性:
LinkedList last = null;
LinkedList current = null;
这2个list放的是待执行的任务,根据属性名就知道last是上次检测时待执行的任务,current是这次检测时要执行的任务,当pendingTasks(当前要执行的任务,克隆给current)不为空且current.equals( last )时认为死锁发生。
死锁发生后,当前任务交给ThreadPerTaskAsynchronousRunner类来处理,这个类会启用新的线程DispatchThread来处理当前的任务队列。
小结
c3p0是现在用的比较广泛的连接池之一,获取连接的效率有待提高,使用jdk1.6之前的可以考虑,jdk1.6及以后的建议使用BoneCP。
从连接池获取的连接,用完了都要关闭,不用怕会关闭物理连接造成无法回收,因为从连接池拿到的连接都是代理的,所以放心调用close方法。