我正在使用 tomcat 连接池。但我遵循例外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"
然后我开始出现以下异常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 块,即自动资源管理,所以我不需要 finally 块。连接关闭由 JDK 自动处理。但为什么这个未包装的连接没有关闭。当我尝试执行以下操作时:
try (Connection poolConn = DataSourceConnectionPool.getConnection();
Connection conn = poolConn.unwrap(OracleConnection.class);
我正进入(状态java.sql.SQLException: Already closed.
那么这种联系有多紧密。我是否必须在不使用 try 块的情况下手动执行此操作?尝试块句柄不应该能够处理这个问题吗?
这是连接池的错误使用。你永远不应该打电话close()
在未包装的连接上。
使用池化连接的正常流程是
- Get the
Connection
,池获取物理连接并将其包装在自己的包装器中返回
- 您使用
Connection
- 你打电话
close()
on the Connection
。这实际上并不close任何东西,池的包装器都会拦截close()
调用并简单地将(仍然活动的)连接返回到池中。
这是有效的,因为池有一个包装类,例如PoolableConnection
that implements Connection
. PoolableConnection
委托底层连接来执行实际工作,但它实现了(除其他外)close()
不同。这会破坏当前的PoolableConnection
包装器并返回底层Connection
到连接池。例如。
这样,您的程序逻辑就可以从DataSource
, 使用Connection
进而close()
,就像正常的、非池化的一样,Connection
.
正是这种透明度使得连接池如此易于使用。
现在,当你打电话时unwrap
, the PooledConnection
让你能够接触到它的内部的、真实的、Connection
代表。
What you要做的就是打电话close()
关于代表!
这有两个效果:
- 它不调用
close()
on PooledConnection
,所以Connection
不会返回到池中。
- 它从池下面关闭底层连接。这应该不是问题,因为池会自行处理断开的连接。
所以你需要非常小心。Always call close()
on the Connection
您已从池中取出,请将其放回池中。Never call 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)