如何阻止c3p0连接池隐藏连接异常的原因?

时间:2013-04-11 20:37:12

标签: mysql c3p0

我有一个使用c3p0进行连接池的应用程序。当连接到数据库时出现任何问题时,我会得到如下例外:

java.sql.SQLException: An SQLException was provoked by the following failure: 
  com.mchange.v2.resourcepool.ResourcePoolException: A ResourcePool cannot acquire 
  a new resource -- the factory or source appears to be down.
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106)
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:65)
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:62)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:531)
    at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
    at com.pontiflex.monitor.dao.ConnectionManager.getConfigReadOnlyDbConnection(Unknown Source)
    at com.pontiflex.monitor.dao.MonitorServiceDAO.getLiveIOCountForOrganization(Unknown Source)        at com.pontiflex.monitor.BillingMonitor.getComparisonValueForActivation(Unknown Source)
    at com.pontiflex.monitor.AbstractMonitor.isMonitoringActive(Unknown Source)
    at com.pontiflex.monitor.AbstractMonitor.generateAlerts(Unknown Source)
    at com.pontiflex.monitor.AbstractMonitor.doMonitoring(Unknown Source)
    at com.pontiflex.monitor.worker.MonitorWorker.run(Unknown Source)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:662)
Caused by: com.mchange.v2.resourcepool.ResourcePoolException: A ResourcePool cannot 
 acquire a new resource -- the factory or source appears to be down.
    at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1279)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557)
    at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:525)
    ... 14 more

无论是网络连接问题,服务器问题(连接太多)还是配置问题,都会出现同样的异常。如果我打开mysql jdbc驱动程序和c3p0的调试日志记录,我会得到更多信息:

WARN  com.mchange.v2.resourcepool.BasicResourcePool  
 com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@4e074784 -- 
 Acquisition Attempt Failed!!! Clearing pending acquires. While trying 
 to acquire a needed new resource, we failed to succeed more than the 
 maximum number of allowed acquisition attempts (30). Last acquisition 
 attempt exception: 
 com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: Data 
 source rejected establishment of connection,  message from server: 
 "Too many connections"
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:921)
    at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1070)
    at com.mysql.jdbc.Connection.createNewIO(Connection.java:2775)
    at com.mysql.jdbc.Connection.<init>(Connection.java:1555)
    at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:285)
    at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:135)
    at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:182)
    at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:171)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:137)
    at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1014)
    at com.mchange.v2.resourcepool.BasicResourcePool.access$800(BasicResourcePool.java:32)
    at com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1810)
    at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)

在没有调整记录器配置的情况下抛出ResourcePoolException时,我能做些什么来让c3p0给我根本原因?

1 个答案:

答案 0 :(得分:4)

SQLException是允许JDBC apis抛出的(已检查)异常,因此c3p0必须“包装”以常规方式不是SQLExceptions的基础异常。如果要检查特定内容,则在这些异常上调用getCause()将传递原始的Throwable。

在你引用的特定例子中,发生了一些不同的事情。问题是记录Exception的Thread不是您的客户端Thread。 c3p0-internal线程从数据库获取Connections。您的客户端线程从池中获取连接。这两个活动与c3p0可以管理的解耦一样 - 这就是拥有连接池的重点。首先,内部线程执行“一轮”采集尝试(默认情况下为30次尝试,延迟时间为1秒,但如果需要,可以重新配置)。

如果获取连接的所有尝试都失败,则c3p0内部线程......

1)记录失败,并在尝试时看到最后一个异常。这是你引用的第二个例外。请注意,这是在WARNING中记录的,而不是DEBUG级别。如果您在INFO上有c3p0日志 - 你应该 - 你会看到这些消息。 [如果你想查看每个单独的Exception,在声明失败之前必须发生的所有30个异常(在defailts下),你需要将记录转为DEBUG(或FINE或ALL)。]

2)在记录采集系列失败后,c3p0将中断wait()客户端并发出ResourcePoolException信号,该信号变为SQLException。这是您引用的第一个例外。发出ResourcePoolException信号。

3)如果breakAfterAcquireFailure设置为false(默认值),则池将从采集失败中恢复。当新客户端进入时,它将再次尝试获取新的Connections。但是,如果breakAfterAcquireFailure设置为true,则池将始终响应具有异常的新客户端请求。

无论如何,我希望这不是完全没有用的。 c3p0可以定义一个自定义的Exception类型,它将成为传递给客户端的包装Exception的原因,因此客户端可以测试代码中的获取失败,但至少目前它没有。抱歉!