Tomcat 连接池:少数方法不释放连接

Tomcat Connection pool : few methods not releasing connection

我正在使用 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()

使用池连接的正常流程是

  1. 获得 Connection,池获得一个物理连接并且 return 它被包装在自己的包装器中
  2. 您使用Connection
  3. 您在 Connection 上呼叫 close()。这实际上并没有 关闭 任何东西,池的包装器拦截了 close() 调用并简单地 return 连接到池。

这是可行的,因为池有一个包装器 class,比如 PoolableConnection implements ConnectionPoolableConnection 委托底层连接执行实际工作,但它的实现方式(除其他事项外)close() 不同。这会破坏当前的 PoolableConnection 包装器和 return 底层 Connection 到连接池。例如。

这样,您的程序逻辑可以从 DataSource 获得连接,使用 Connection,然后使用 close(),就像正常的未连接的 [=12] =].

正是这种透明性使得连接池如此易于使用。

现在,当您调用 unwrap 时,PooledConnection 允许您访问它的内部、真实的 Connection 委托。

所做的就是调用close()委托!

这有两个作用:

  1. 它不会在 PooledConnection 上调用 close(),因此 Connection 不会 return 进入池。
  2. 它从池下面关闭底层连接。这应该不是问题,因为池会自行处理断开的连接。

所以你需要非常小心。 总是 调用 close() 你从池中得到的 Connection,return 到池中。 从不 在基础连接上调用 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