C3P0 连接分析
最近在看C3P0的原理,还是将C3P0的源码导入到Ecplise中debug看得清楚多了。下面记录我debug的经历。
1.下载c3p0的jar和源码,这个百度吧。
2.导入jar和源码到java工程中,导入后,会发现有些错误的,把junit的类去掉,有的提示没有实现一些方法,就加进去,还有的提示要删除多余的实现方法,就删除掉吧,这样下来,基本上不报错了。
3.debug的过程中,有些类没有源码的,到google上去搜,会有源码的,写一个对应的java类加进工程里去就行了。
1.写一个连接池的简单的工具类
public class ConnectionPool { private static ComboPooledDataSource ds; public synchronized static final Connection getConnection() { try { if (ds != null) { return ds.getConnection(); } else{ ds = new ComboPooledDataSource(true); ds.setJdbcUrl("jdbc:mysql://192.168.1.102:3306/S10"); try { ds.setDriverClass("com.mysql.jdbc.Driver"); } catch (PropertyVetoException e) { // TODO Auto-generated catch block e.printStackTrace(); } ds.setUser("root"); ds.setPassword("123456"); ds.setInitialPoolSize(10); ds.setMinPoolSize(10); ds.setMaxPoolSize(20); ds.setMaxIdleTime(30); return ds.getConnection(); } } catch (SQLException e) { e.printStackTrace(); } return null; } }2. 现在需要debug的代码是
ds.getConnection(),看看它的执行顺序吧。
首先进入的是AbstractPoolBackedDataSource中的getConnection方法
pc = getPoolManager().getPool().checkoutPooledConnection(); return pc.getConnection();
其中:getPoolManager().getPool()是获取连接池,它对应的类是C3P0PooledConnectionPoolManager,它管理着连接池的生命周期。
C3P0PooledConnectionPoolManager中有一个内部类PooledConnectionResourcePoolManager,它里面会创建BasicResourcePool,BasicResourcePool才是真正创建连接的地方。
会调用里面的私有方法。
private void _recheckResizePool() { assert Thread.holdsLock(this); if (! broken) { int msz = managed.size(); int shrink_count; int expand_count; if ((shrink_count = msz - pending_removes - target_pool_size) > 0) shrinkPool( shrink_count ); else if ((expand_count = target_pool_size - (msz + pending_acquires)) > 0) expandPool( expand_count ); } }
继续跟踪expandPool()方法,这里的expand_count是初始值10.
private void expandPool(int count) { assert Thread.holdsLock(this); // XXX: temporary switch -- assuming no problems appear, we'll get rid of AcquireTask // in favor of ScatteredAcquireTask if ( USE_SCATTERED_ACQUIRE_TASK ) { for (int i = 0; i < count; ++i) taskRunner.postRunnable( new ScatteredAcquireTask() ); } else { for (int i = 0; i < count; ++i) taskRunner.postRunnable( new AcquireTask() ); } }
进入到AcquireTask()方法里看到如下的代码。
BasicResourcePool.this.doAcquire(); Object resc = mgr.acquireResource();
acquireResource()方法会调用一个内部类PooledConnectionResourcePoolManager,它会调用下面的代码。
if ( connectionCustomizer == null) { out = (auth.equals( C3P0ImplUtils.NULL_AUTH ) ? cpds.getPooledConnection() : cpds.getPooledConnection( auth.getUser(), auth.getPassword() ) ); }
上面的代码调用下面的代码
protected PooledConnection getPooledConnection(String user, String password, ConnectionCustomizer cc, String pdsIdt) throws SQLException { // 它里面包含jdbcUrl等信息 DataSource nds = getNestedDataSource(); if (nds == null) throw new SQLException( "No standard DataSource has been set beneath this wrapper! [ nestedDataSource == null ]"); // 这里的代码调用是在DriverManagerDataSource中实现的 Connection conn = nds.getConnection(user, password); if (conn == null) throw new SQLException("An (unpooled) DataSource returned null from its getConnection() method! " + "DataSource: " + getNestedDataSource()); if ( this.isUsesTraditionalReflectiveProxies() ) { //return new C3P0PooledConnection( new com.mchange.v2.c3p0.test.CloseReportingConnection( conn ), return new C3P0PooledConnection( conn, connectionTester, this.isAutoCommitOnClose(), this.isForceIgnoreUnresolvedTransactions(), cc, pdsIdt); } else { return new NewPooledConnection( conn, connectionTester, this.isAutoCommitOnClose(), this.isForceIgnoreUnresolvedTransactions(), this.getPreferredTestQuery(), cc, pdsIdt); } }
public Connection getConnection(String username, String password) throws SQLException { ensureDriverLoaded(); // 这才是真实的物理连接啊 Connection out = driver().connect( jdbcUrl, overrideProps(username, password) ); if (out == null) throw new SQLException("Apparently, jdbc URL '" + jdbcUrl + "' is not valid for the underlying " + "driver [" + driver() + "]."); return out; }
至此,初始化的10个连接完成了。