問題
Mysql服務器默認的“wait_timeout”是8小時,也就是說一個connection空閑超過8個小時,Mysql將自動斷開該connection。
可以用show global variables LIKE'wait_timeout';查看mysql的等待時間。
這就是問題的所在,在連接池中的connections如果空閑超過8小時,Mysql將其斷開,而C3P0並不知道該connection已經失效,如果這時有Client請求connection,連接池將該失效的Connection提供給Client,將會造成上面的異常。
解決方案
- 增加 wait_timeout 的時間。
- 減少 Connection pools 中 connection 的 lifetime。
- 測試 Connection pools 中 connection 的有效性。
最好的辦法是同時綜合使用上述3種方法,下面就 DBCP、C3P0 和 simple jdbc dataSource 分別做一說明,假設 wait_timeout 為默認的8小時
配置Mysql的wait_timeout
對於 MySQL5 之前的版本,如 Mysql4.x,只需要修改連接池配置中的 URL,添加一個參數:autoReconnect=true(如jdbc:mysql://hostaddress:3306/schemaname?autoReconnect=true),如果是 MySQL5 及以后的版本,則需要修改 my.cnf(或者my.ini) 文件,在 [mysqld] 后面添加上:
wait_timeout = 28800
interactive-timeout = 28800
DBCP
#驗證使用的SQL語句 validationQuery SELECT 1 #池中的連接空閑30(1800000ms)分鍾后被回收 minEvictableIdleTimeMillis 1800000 #每30(30000ms)秒運行一次空閑連接回收器 timeBetweenEvictionRunsMillis 30000 #借出連接時不要測試,否則很影響性能 testOnBorrow false testWhileIdle true #程序中的連接不使用后是否被連接池回收 #DBCP 2.0.1 (該版本要使用removeAbandonedOnMaintenance和removeAbandonedOnBorrow) #removeAbandoned=true removeAbandonedOnMaintenance=true removeAbandonedOnBorrow=true #數據庫連接過多長時間不用將被視為被遺棄而收回連接池中(單位秒)。(為配合測試程序默認為30秒,一定要小於maxWait) removeAbandonedTimeout=30
C3P0
//獲取connnection時測試是否有效 testConnectionOnCheckin = true //自動測試的table名稱 automaticTestTable=C3P0TestTable //set to something much less than wait_timeout, prevents connections from going stale idleConnectionTestPeriod = 18000 //set to something slightly less than wait_timeout, preventing 'stale' connections from being handed out maxIdleTime = 25000 //if you can take the performance 'hit', set to "true" testConnectionOnCheckout = true
simple jdbc dataSource
Pool.PingQuery = select 1 Pool.PingEnabled = true Pool.PingConnectionsOlderThan = 0 //對於空閑的連接一個小時檢查一次 Pool.PingConnectionsNotUsedFor = 3600000