4

我有一个使用 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)

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

4

1 回答 1

4

SQLException is the (checked) Exception that JDBC apis are permitted to throw, so c3p0 must "wrap" underlying Exceptions that ate not SQLExceptions in the usual way. Calling getCause() on these Exceptions will deliver the original Throwable if you want to check for something specific.

In the particular example you cite, something different is going on. The issue is that the Thread which is logging the Exception is not your client Thread. c3p0-internal Threads acquire Connections from the database. Your client Threads acquire Connections from the pool. The two activities are as uncoupled as c3p0 can manage -- that is the whole point of having a Connection pool. First, internal Threads perform a "round" of acquisition attempts (by default 30 attempts with a 1 sec delay between, but you can reconfigure if you want).

If ALL of the attempts to acquire a Connection fail, the c3p0 internal threads...

1) Log the failure, and the last Exception seen while trying. This is the second Exception you quote. Note that this is logged at WARNING, not a DEBUG level. If you have c3p0 logging at INFO -- which you should -- you'll see these messages. [If you want to see each individual Exception, all 30 of the Exceptions that must occur (under defailts) before declaring a failure, you need to turn logging to DEBUG (or FINE or ALL).]

2) After logging that an acquisition series has failed, c3p0 will interrupt wait()ing clients and signal a ResourcePoolException, which becomes gets in an SQLException. This is the first Exception you quote. A ResourcePoolException is signalled.

3) if breakAfterAcquireFailure is set to false (the default), the pool will recover from an acquisition failure. It will try again to acquire new Connections as new clients come in.. If breakAfterAcquireFailure is set to true, however, the pool will always respond to new client requests with an Exception.

Anyway, I hope this isn't entirely unhelpful. c3p0 could define a custom Exception type that would become the cause of the wrapped Exception delivered to clients, so clients could test for an acquisition failure in code, but for now at least it does not. (Sorry!)

于 2013-04-12T05:46:15.393 回答