2011-10-19 30 views
4

在最新版本的DBCP和C3P0上,使用Spring的Ibatis支持,我遇到了两个泄漏连接的问题。带C3P0或DBCP的Spring ORM正在泄漏连接

该方案是有一个运行SQL的日志锁定多个表。这会导致我的池中的连接在用户触发锁定表的查询时最大化。最后,管理员进入MySQL并在长时间运行的SQL上执行kill query <id>

如果有足够的线程(在我的周围50个或更多的情况下),它正在等待绕了DB线程在游泳池进行检查回来,然后我看到类似线程转储如下:

java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1315) 
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557) 
    - locked <0x00002aaacbb01118> (a com.mchange.v2.resourcepool.BasicResourcePool) 
    at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477) 
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:525) 
    at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128) 
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:113) 
    at 

java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    at java.lang.Object.wait(Object.java:485) 
    at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1104) 
    - locked <0x00002aab0f030620> (a org.apache.commons.pool.impl.GenericObjectPool$Latch) 
    at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106) 
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) 
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:113) 
    at 

和这些线程等待撒手人寰。

如果该池已最大化,并且只有少数(约5个)线程正在等待池中的空闲连接,则不会发生这种情况。

我知道有配置可以解决这个问题(设置超时等),但我有兴趣为什么这是发生在第一个地方?为什么当有50个或更多的线程在等待连接,并且我终止了长时间运行的SQL时,活动线程不会返回到池中?

更新:我应该明确表示,我使用Spring 3.0.2和 ibatis的2.3。我使用SqlMapClientTemplate,它为我管理我的 连接。此时,我开始认为它是 Ibatis 2.3没有正确处理重负载。

+3

您是否在执行查询后关闭连接? – BalusC

+0

@BalusC我对Spring使用ComboPooledDataSource或BasicDataSource,所以我不管理在我的Java代码中关闭这些连接的open c。也许春天是问题。 – stevebot

+0

你应该显示一些你如何使用连接的代码。仅仅因为你使用Spring来管理数据源,并不意味着它会为你关闭连接。 – Nick

回答

2

很像@BalusC问,你关闭你的连接吗?他们应该在您的Java try-catch-finallyfinally条款中关闭。每一个的环绕connection.close()方法在自己的try { con.close() } catch (Exception ignore) {}

可选,你应该这样做的ResultSet然后Statement然后Connection的顺序。在您的初始try块之外声明您的Connection,StatementResultSet作为null并在您的try块中实例化。

Connection con = null; 
Statement stmt = null; 
ResultSet rs = null; 

try { 

    con = getConnectionFromPoolMethod(); 

    // ... 
    // instantiate your statement and result set as normal 
    // make your sql call; 
    // extract data from result set to appropriate POJO 

} catch (Exception ex) { 
    // handle your exception, log, wrap, enhance or rethrow or whatever 
} finally { 
    if (rs != null) try { rs.close(); } catch (Exception ignore) {} 
    if (stmt != null) try { stmt.close(); } catch (Exception ignore) {} 
    if (con != null) try { con.close(); } catch (Exception ignore) {} 
} 

如果你为它,而不是在每个finally一个封装了SQL调用所有上面的代码,你可以选择使用DbUtils实用类Apache Commons DbUtils

import org.apache.commons.dbutils.DbUtils; 

并应用closeQuietly方法。该finally块看起来是这样,而不是:

} finally { 
    DbUtils.closeQuietly(con, stmt, rs); 
} 
+0

+1没问题 - 很好的答案。不要吝啬挑剔,但捕捉特定的检查异常,比如“SQLException”比捕捉纯粹的Exception更好。 –

+0

这是更好的做法,但是如果我猜测他是新人,他可能不会考虑导入另一个班级。暂时编辑添加选项以使用DbUtils。 – JoshDM

+0

@FredCheese我的Java代码没有管理这些连接。我创建数据源,然后将其传递给SqlMapClientTemplate,它是一个Spring对象。因此,我从来不需要管理关闭连接。 – stevebot

2

只需添加到@ BalusC的评论和@JoshDM's answer,当你调用在你的Java代码Connectionclose(),幕后这实际上只是检查连接回您的连接池而不是物理上关闭它。这就是为什么始终通过Java代码关闭连接非常重要的原因,无论底层JDBC驱动程序是否将它们集中在一起。这个在this post

更多的讨论。

4

当使用C3PO,我强烈建议尝试这种feature。当您在事务外执行数据库修改时,通常会出现连接泄漏。与未完成写入的连接无法重用并从池中丢失。如果在相当长的超时时间内启用此调试,您将能够看到具有可疑数据库操作的堆栈跟踪。

确保在堆栈跟踪看到的操作正确管理事务。还可以通过将c3p0记录器设置为调试级别来监视连接池的使用情况。

+0

谢谢,DBCP也有一个名为removeAbandoned的类似配置。当我将其删除时,我看到我失去了联系。我仍然不知道为什么应用程序正在丢失这些连接。 – stevebot

+0

我对dbcp不熟悉,但是我通过c3p0 debugUnreturnedConnectionStackTraces跟踪了很多连接泄漏。请记住,您将看到的堆栈跟踪是在从池中取出连接时生成的。这意味着您将看到导致连接丢失的确切呼叫。然后确保在上面的sql调用中有@Transactional或同等变更数据库。 – mrembisz

+0

谢谢,c3p0可能比dbcp更冗长。可悲的是,这部分代码不支持事务。 – stevebot