关于c3p0在debug模式下控制台抛出的如下异常:
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:566)
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:234)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:470)
at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:964)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
或者:
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:566)
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:234)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolManager.initializeAutomaticTestTable(C3P0PooledConnectionPoolManager.java:834)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolManager.createPooledConnectionPool(C3P0PooledConnectionPoolManager.java:696)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolManager.getPool(C3P0PooledConnectionPoolManager.java:257)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolManager.getPool(C3P0PooledConnectionPoolManager.java:271)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getNumThreadsAwaitingCheckoutDefaultUser(AbstractPoolBackedDataSource.java:203)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.mchange.v2.beans.BeansUtils.extractAccessiblePropertiesToMap(BeansUtils.java:359)
at com.mchange.v2.beans.BeansUtils.appendPropNamesAndValues(BeansUtils.java:324)
at com.mchange.v2.c3p0.ComboPooledDataSource.toString(ComboPooledDataSource.java:539)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getPoolManager(AbstractPoolBackedDataSource.java:462)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
at org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction.java:81)
at org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction.java:67)
at org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor.java:279)
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:72)
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:59)
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:137)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:96)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:77)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:108)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102)
通常在日志中包含上述信息之后,其紧接着的上下面会包含类似如下信息:
17-03-08 16:37:00 DEBUG com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2 com.mchange.v2.resourcepool.BasicResourcePool: Preparing to destroy resource: com.mchange.v2.c3p0.impl.NewPooledConnectio
n@1070779f
17-03-08 16:37:00 DEBUG com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2 com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool: Preparing to destroy PooledConnection: com.mchange.v2.c3p0.impl.NewPoo
ledConnection@1070779f
17-03-08 16:37:00 DEBUG com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2 com.mchange.v2.c3p0.impl.NewPooledConnection: com.mchange.v2.c3p0.impl.NewPooledConnection@1070779f closed by a client.
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:566)
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:234)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:470)
at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:964)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
17-03-08 16:37:00 DEBUG com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2 com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool: Successfully destroyed PooledConnection: com.mchange.v2.c3p0.impl.NewP
ooledConnection@1070779f
17-03-08 16:37:00 DEBUG com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2 com.mchange.v2.resourcepool.BasicResourcePool: Successfully destroyed resource: com.mchange.v2.c3p0.impl.NewPooledConnect
ion@1070779f
比如initializeAutomaticTestTable处源码为:
// only called from sync'ed methods private String initializeAutomaticTestTable(String automaticTestTable, DbAuth auth) throws SQLException { PooledConnection throwawayPooledConnection = auth.equals( defaultAuth ) ? cpds.getPooledConnection() : cpds.getPooledConnection(auth.getUser(), auth.getPassword()); Connection c = null; PreparedStatement testStmt = null; PreparedStatement createStmt = null; ResultSet mdrs = null; ResultSet rs = null; boolean exists; boolean has_rows; String out; try { c = throwawayPooledConnection.getConnection(); DatabaseMetaData dmd = c.getMetaData(); String q = dmd.getIdentifierQuoteString(); String quotedTableName = q + automaticTestTable + q; out = "SELECT * FROM " + quotedTableName; mdrs = dmd.getTables( null, null, automaticTestTable, new String[] {"TABLE"} ); exists = mdrs.next(); //System.err.println("Table " + automaticTestTable + " exists? " + exists); if (exists) { testStmt = c.prepareStatement( out ); rs = testStmt.executeQuery(); has_rows = rs.next(); if (has_rows) throw new SQLException("automatic test table '" + automaticTestTable + "' contains rows, and it should not! Please set this " + "parameter to the name of a table c3p0 can create on its own, " + "that is not used elsewhere in the database!"); } else { String createSql = "CREATE TABLE " + quotedTableName + " ( a CHAR(1) )"; try { createStmt = c.prepareStatement( createSql ); createStmt.executeUpdate(); } catch (SQLException e) { if (logger.isLoggable( MLevel.WARNING )) logger.log(MLevel.WARNING, "An attempt to create an automatic test table failed. Create SQL: " + createSql, e ); throw e; } } return out; } finally { ResultSetUtils.attemptClose( mdrs ); ResultSetUtils.attemptClose( rs ); StatementUtils.attemptClose( testStmt ); StatementUtils.attemptClose( createStmt ); ConnectionUtils.attemptClose( c ); try{ if (throwawayPooledConnection != null) throwawayPooledConnection.close(); } catch ( Exception e ) { //e.printStackTrace(); logger.log(MLevel.WARNING, "A PooledConnection failed to close.", e); } } }
可知,它是被开发人员有意关闭的。
比如上面的close原因是idle超过时间,还有初始化c3p0test表后该连接主动关闭,当然还可能有其他原因。close出的关键源码如下:
private void close( Throwable cause ) throws SQLException { if ( this.invalidatingException == null ) { List closeExceptions = new LinkedList(); // cleanup ResultSets cleanupResultSets( closeExceptions ); // cleanup uncached Statements cleanupUncachedStatements( closeExceptions ); // cleanup cached Statements try { closeAllCachedStatements(); } catch ( SQLException e ) { closeExceptions.add(e); } // cleanup physicalConnection try { physicalConnection.close(); } catch ( SQLException e ) { if (logger.isLoggable( MLevel.FINER )) logger.log( MLevel.FINER, "Failed to close physical Connection: " + physicalConnection, e ); closeExceptions.add(e); } // update our state to bad status and closed, and log any exceptions if ( connection_status == ConnectionTester.CONNECTION_IS_OKAY ) connection_status = ConnectionTester.CONNECTION_IS_INVALID; if ( cause == null ) { this.invalidatingException = NORMAL_CLOSE_PLACEHOLDER; if ( logger.isLoggable( MLevel.FINEST ) ) logger.log( MLevel.FINEST, this + " closed by a client.", new Exception("DEBUG -- CLOSE BY CLIENT STACK TRACE") ); logCloseExceptions( null, closeExceptions ); if (closeExceptions.size() > 0) throw new SQLException("Some resources failed to close properly while closing " + this); } else { this.invalidatingException = cause; if (Debug.TRACE >= Debug.TRACE_MED) logCloseExceptions( cause, closeExceptions ); else logCloseExceptions( cause, null ); } } }
从上面的流程+日志,我们也可确定它是被有意关闭的。所以确定c3p0的这些日志原因和作用还是要通过上下文代码来理解。在看之前,网上搜了一遍,讲得目的不对马嘴,就像一个中学生问“如何才能英语考高分”,你却回答人家“为什么要学英语”。