Tomcat连接池:几种不释放连接的方法

时间:2015-01-17 17:27:38

标签: java tomcat jdbc connection-pooling

我正在使用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块?不应该尝试块句柄能够处理这个吗?

1 个答案:

答案 0 :(得分:10)

这是对连接池的错误使用。你永远不应该在未打开的连接上调用close()

使用池化连接的正常流程是

  1. 获取Connection,池获取物理连接并将其包装在自己的包装器中
  2. 您使用Connection
  3. 您在close()上致电Connection。这实际上并不是关闭任何东西,池的包装器拦截close()调用并简单地返回到池中的(仍处于活动状态)连接。
  4. 这是有效的,因为池有一个包装类,比如PoolableConnection implements ConnectionPoolableConnection委托基础连接进行实际工作,但它以不同的方式实现close()({1}}。这会破坏当前的PoolableConnection包装器,并将底层Connection返回到连接池。例如。

    这样,您的程序逻辑可以从DataSource获得连接,使用Connection然后使用close(),就像正常的,未加密的Connection一样

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

    现在,当您致电unwrap时,PooledConnection可让您访问其内部,真实的Connection代表。

    您所做的是在代理上致电close()

    这有两个影响:

    1. 它不会在close()上调用PooledConnection,因此Connection不会返回到池中。
    2. 它关闭了游泳池下面的底层连接。这应该不是问题,因为池本身会处理掉线连接。
    3. 所以你需要非常小心。 始终在您从池中获取的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