12

当我尝试在 MySQL 数据库上使用 C3P0 执行一些简单的读取 (SELECT) 操作时,会发生中断异常 (java.lang.InterruptedException)。当我将并行线程的数量增加到 100 以上时会发生异常(我尝试过使用 5、10、20、60 和 100)。我执行的语句很简单:

SELECT `Model.id` FROM `Model` LIMIT 100;

我的连接是从使用以下属性配置的 ComboPooledDataSource 汇集的(另请参见C3P0 手册):

c3p0.jdbcUrl=jdbc:mysql... 
c3p0.debugUnreturnedConnectionStackTraces=true
c3p0.maxIdleTime=5
c3p0.maxPoolSize=1000
c3p0.minPoolSize=5
c3p0.initialPoolSize=5
c3p0.acquireIncrement=3
c3p0.acquireRetryAttempts=50
c3p0.numHelperThreads=20
c3p0.checkoutTimeout=0
c3p0.testConnectionOnCheckin=true
c3p0.testConnectionOnCheckout=true
user=***
password=***

我运行测试的机器上的 MySQL 服务器配置为接受 1024 个连接,并且我运行的单元测试已成功执行(数据按预期从数据库中检索)。但是,在 C3P0 日志文件中,我发现以下警告:

15:36:11,449  WARN BasicResourcePool:1876 - com.mchange.v2.resourcepool.BasicResourcePool@9ba6076 -- Thread unexpectedly interrupted while performing an acquisition attempt.
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1805)
    at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)

我想知道该警告的原因以及它可能对软件的稳健性和稳定性产生的影响。请注意,使用后,我关闭了结果集、SQL 语句和连接。最后,一旦测试结束,我通过调用方法关闭池ComboPooledDataSource#close()。更奇怪的是(并且似乎揭示了同步问题),如果我使用以下命令给池足够的时间......

Thread.sleep(10000); // wait for some time
datasource.close();

日志中不会出现任何警告!你认为这会引发 C3P0 的线程安全问题,还是我做错了什么?

更新1:

让我提一下Thread.sleep(10000),除了已经提到的内容之外,删除 会导致 MySQL 日志文件中记录以下信息:

110221 14:57:13 [Warning] Aborted connection 9762 to db: 'myDatabase' user: 'root'
host: 'localhost' (Got an error reading communication packets)

可能会更亮一些...

更新 2:

这是我的 MySQL 服务器配置。服务器允许的最大连接数设置为 1024(如上所述),这对于我想要做的事情来说已经足够了。

[mysqld]
max_allowed_packet  = 64M
thread_concurrency      = 8
thread_cache_size       = 8
thread_stack        = 192K
query_cache_size = 0
query_cache_type = 0
max_connections = 1024
back_log = 50
innodb_thread_concurrency = 6
innodb_lock_wait_timeout = 120
log_warnings

为了混淆任何疑问,我验证了最大连接数是通过以下方式正确设置的:

show global variables where Variable_name='max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 1024  | 
+-----------------+-------+
1 row in set (0.00 sec)
4

3 回答 3

7

该警告来自此处的 2007 行左右。这似乎是一个试图获取连接的线程。

可能是因为池设置为获取比 mysql 服务器配置处理的连接更多的连接。这似乎是有道理的,因为默认的max_connection是 100(或 151,具体取决于您的 mysql 版本)

因此,尝试获取连接的线程进入睡眠()/重试循环以尝试获取连接 - 但是当它在该循环内时关闭整个池 - 该线程被中断,因此当您关闭时可以回收所有资源水池。

到目前为止,似乎没有造成任何伤害,您的代码可能会在完成后将连接返回到池,让它们空闲供其他人使用,并且您的所有查询都会通过。

于 2011-02-21T17:21:03.227 回答
1

也许,InterruptedException是正常的,因为一些 c3p0 线程正在等待连接,当你调用close()这些线程时,这些线程被中断了。但是,根据您的设置(100 个客户端,1000 个服务器连接),等待资源的必要性并不那么明显。
如果您真的感兴趣,最可靠的解决方案可能是查看 c3p0 日志,添加更多日志并重新编译......

于 2011-02-16T15:09:47.300 回答
1

我刚刚遇到了这个问题。这是我对数据源的设置:

 [java:comp/env/jdbc/pooledDS] = [com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 2siwtu8o4m410i1l4tkxb|187c55c, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> null, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 2siwtu8o4m410i1l4tkxb|187c55c, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]]

并固定:

[java:comp/env/jdbc/pooledDS] = [com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 2siwtu8o4m5kux117kgtx|13e754f, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> oracle.jdbc.driver.OracleDriver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 2siwtu8o4m5kux117kgtx|13e754f, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:oracle:thin:@localhost:1521:oracle, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]]

因此,并非所有内容都设置正确。更具体地说,当我调用setDriverClasssetJdbcUrl纠正空值时,我消除了 InterruptedException

于 2012-06-21T20:03:32.367 回答