C3P0是线程安全的吗?

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

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个连接,并且我运行的unit testing成功执行(数据按预期从数据库中检索)。 但是,在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 

为了模糊任何疑问,我validation了最大连接数是通过以下方式正确设置的:

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

这个警告来自2007年左右的线路。 它似乎是一个试图获取连接的线程。

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

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

到目前为止,似乎没有任何损害,当你完成它时,你的代码可能会返回到池的连接,让它们闲置供其他人使用,并且你的所有查询都可以通过。

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

我刚遇到这个问题。 这是我对DataSource的设置:

  [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