我正在使用 tomcat 连接池。但我正在关注异常
org.apache.tomcat.dbcp.dbcp.SQLNestedException:无法获取连接,池错误等待空闲对象超时
所以我在 context.xml 中添加了以下几行来查找泄漏:
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 以访问特定于驱动程序的连接。
try (Connection conn = DataSourceConnectionPool.getConnection().unwrap(OracleConnection.class);
OracleCallableStatement cstmt = (OracleCallableStatement) conn.prepareCall(MIGRATE_ACCOUNT)) {
...
....
)
重要的是要注意我正在使用 JDK7 的 try block ,即自动资源管理,所以我不需要 finally block 。连接关闭由 JDK 自动处理。但是为什么这个未包装的连接没有关闭。当我尝试执行以下操作时:
try (Connection poolConn = DataSourceConnectionPool.getConnection();
Connection conn = poolConn.unwrap(OracleConnection.class);
我收到 java.sql.SQLException: Already closed.
那么如何关闭此连接。我是否必须在不使用 try block 的情况下手动完成?不应该尝试 block 句柄能够处理这个吗?
最佳答案
这是对连接池的错误使用。永远不要在未包装的连接上调用 close()
。
使用池连接的正常流程是
- 获取
Connection
,池获取物理连接并将其包装在自己的包装器中返回 - 您使用
连接
- 您在
Connection
上调用close()
。这实际上并没有关闭任何东西,池的包装器拦截了close()
调用并简单地将(仍处于 Activity 状态的)连接返回到池。
这是可行的,因为池有一个包装器类,比如PoolableConnection
,它实现了Connection
。 PoolableConnection
委托(delegate)底层连接执行实际工作,但它以不同方式实现(除其他事项外)close()
。这会破坏当前的 PoolableConnection
包装器并将底层 Connection
返回到连接池。例如。
这样,您的程序逻辑就可以从DataSource
获取连接,使用Connection
然后使用close()
,就像它一样将是一个正常的、未合并的 Connection
。
正是这种透明性使得连接池如此易于使用。
现在,当您调用 unwrap
时,PooledConnection
允许您访问它的内部、真实的 Connection
委托(delegate)。
您所做的是调用 close()
委托(delegate)!
这有两个作用:
- 它不会在
PooledConnection
上调用close()
,因此Connection
不会返回到池中。 - 它关闭了池下方的底层连接。这应该不是问题,因为池会自行处理断开的连接。
所以你需要非常小心。 始终在您从池中获得的Connection
上调用close()
,将其返回到池中。 永远不要在底层连接上调用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
关于java - Tomcat 连接池 : few methods not releasing connection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28002176/