Java Tomcat连接池:很少有方法不释放连接
我正在使用tomcat连接池。但我遵循的是例外Java Tomcat连接池:很少有方法不释放连接,java,tomcat,jdbc,connection-pooling,Java,Tomcat,Jdbc,Connection Pooling,我正在使用tomcat连接池。但我遵循的是例外 org.apache.tomcat.dbcp.dbcp.SQLNestedException:无法获取连接,池错误等待空闲对象超时 因此,我在context.xml中放入以下行以查找漏洞: removeAbandoned=“true”logaudded=“true”removeAbandonedTimeout=“3” 然后我开始得到以下异常org.apache.tomcat.dbcp.dbcp.弃置trace$弃置对象异常:由以下代码创建的dbcp
org.apache.tomcat.dbcp.dbcp.SQLNestedException:无法获取连接,池错误等待空闲对象超时
因此,我在context.xml中放入以下行以查找漏洞:
removeAbandoned=“true”logaudded=“true”removeAbandonedTimeout=“3”
然后我开始得到以下异常org.apache.tomcat.dbcp.dbcp.弃置trace$弃置对象异常:由以下代码创建的dbcp对象从未关闭:
所以我发现了两种导致泄漏的罪魁祸首方法。这两种方法具有获取连接的通用方法,即调用unwrap来访问特定于驱动程序的连接
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:已经关闭。
那么这个连接有多近。我是否必须在不使用try块的情况下手动执行此操作?不应该尝试块句柄来处理此问题吗?这是不正确的连接池用法。决不能在未包装的连接上调用close()
try (Connection conn = DataSourceConnectionPool.getConnection().unwrap(OracleConnection.class);
OracleCallableStatement cstmt = (OracleCallableStatement) conn.prepareCall(MIGRATE_ACCOUNT)) {
...
....
)
使用池连接的正常流程是
连接
,池将获取一个物理连接,并将其包装在自己的包装器中返回连接
连接上调用close()
。这实际上并没有关闭任何东西,池的包装器截取close()
调用并简单地返回到池的连接(仍然处于活动状态)
PoolableConnection
,它实现连接
PoolableConnection
委托基础连接执行实际工作,但它实现(除其他外)close()
的方式不同。这将销毁当前的PoolableConnection
包装器,并将正在运行的连接
返回到连接池。比如说
这样,您的程序逻辑可以从数据源
获取连接,使用连接
,然后使用关闭()
,就像正常的、未冷却的连接一样
正是这种透明性使得连接池如此易于使用
现在,当您调用unwrap
时,PooledConnection
允许您访问它的内部真正的连接
您要做的是对代理调用close()
这有两个影响:
它不会在PooledConnection
上调用close()
,因此连接不会返回到池中
它从池底关闭下引连接。这应该不是问题,因为池本身会处理断开的连接
所以你需要非常小心始终在从池中获取的连接上调用close()
,将其返回到池中从不对基础连接调用close()
try (Connection conn = DataSourceConnectionPool.getConnection().unwrap(OracleConnection.class);
OracleCallableStatement cstmt = (OracleCallableStatement) conn.prepareCall(MIGRATE_ACCOUNT)) {
...
....
)
因此,您的代码应该是:
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
我的第一个问题是,您如何能够验证.unwrap()代码是泄漏发生的地方?