我正在使用tomcat连接池。但是我在跟踪异常 org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object
org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object
所以我在context.xml中放入以下行以查找泄漏: removeAbandoned="true" logAbandoned="true" removeAbandonedTimeout="3"
removeAbandoned="true" logAbandoned="true" removeAbandonedTimeout="3"
然后,我开始跟踪异常,org.apache.tomcat.dbcp.dbcp.AbandonedTrace$AbandonedObjectException: DBCP object created 2015-01-17 22:12:18 by the following code was never closed: 因此发现了导致此泄漏的两种罪魁祸首方法。两种方法都有获得连接的通用方法,即调用unwrap获得对驱动程序特定连接的访问权限。
org.apache.tomcat.dbcp.dbcp.AbandonedTrace$AbandonedObjectException: DBCP object created 2015-01-17 22:12:18 by the following code was never closed:
try (Connection conn = DataSourceConnectionPool.getConnection().unwrap(OracleConnection.class); OracleCallableStatement cstmt = (OracleCallableStatement) conn.prepareCall(MIGRATE_ACCOUNT)) { ... .... )
需要注意的重要思想是,我正在使用来自JDK7的try块,即“自动资源管理”,因此我不需要finally块。连接关闭由JDK自动处理。但是为什么这个展开的连接没有关闭。当我尝试执行以下操作时:
try (Connection poolConn = DataSourceConnectionPool.getConnection(); Connection conn = poolConn.unwrap(OracleConnection.class);
我正在获得java.sql.SQLException: Already closed.如此紧密的联系。我是否必须手动执行而不使用try块?不应该尝试阻止句柄来处理吗?
java.sql.SQLException: Already closed.
这是对连接池的不正确使用。您永远不应调用close()未包装的连接。
close()
使用池连接的正常流程是
Connection
之所以有效,是因为该池具有包装器类,PoolableConnection即that implements Connection。PoolableConnection委托底层连接来执行实际工作,但是(除其他事项外)实现方式close()有所不同。这将破坏当前的PoolableConnection包装,并将底层组件返回Connection到连接池。例如。
PoolableConnection
implements Connection
这样,您的程序逻辑就可以从中获取连接,然后DataSource使用Connection和close(),就像正常的非池化一样Connection。
DataSource
正是这种透明性使连接池易于使用。
现在,当您调用时unwrap,PooledConnection您就可以访问它的内部真实Connection委托。
unwrap
PooledConnection
什么 ,你 要做的就是调用close() 的委托 !
这有两个效果:
因此,您需要非常小心。 总是 叫close()上Connection你已经从池中得到,将其返回到池中。 永远不要 调用close()基础连接。
因此,您的代码应为:
try (final Connection poolConn = DataSourceConnectionPool.getConnection()) { final Connection conn = poolConn.unwrap(OracleConnection.class); //do stuff with conn //do not close conn!! } //poolConn is returned to the pool