異常信息
org.hibernate.exception.JDBCConnectionException: could not execute query
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:
74
)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:
43
)
.......
Caused by: com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: No operations allowed after connection closed.Connection was implicitly closed due to underlying exception/error:
** BEGIN NESTED EXCEPTION **
com.mysql.jdbc.CommunicationsException
MESSAGE: Communications link failure due to underlying exception:
** BEGIN NESTED EXCEPTION **
java.net.SocketException
MESSAGE: Broken pipe
STACKTRACE:
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
......
** END NESTED EXCEPTION **
|
原因分析
查看了Mysql的文檔,以及Connector/J的文檔以及在線說明發現,出現這種異常的原因是:
Mysql服務器默認的“wait_timeout”是8小時,也就是說一個connection空閑超過8個小時,Mysql將自動斷開該connection。這就是問題的所在,在C3P0 pools中的connections如果空閑超過8小時,Mysql將其斷開,而C3P0並不知道該connection已經失效,如果這時有Client請求connection,C3P0將該失效的Connection提供給Client,將會造成上面的異常。
解決方案
解決的方法有3種:
- 增加 wait_timeout 的時間。
- 減少 Connection pools 中 connection 的 lifetime。
- 測試 Connection pools 中 connection 的有效性。
當然最好的辦法是同時綜合使用上述3種方法,下面就 DBCP、C3P0 和 simple jdbc dataSource 分別做一說明,假設 wait_timeout 為默認的8小時
DBCP 增加以下配置信息:
validationQuery = "select 1"
testWhileIdle = "true"
//some positive integer
timeBetweenEvictionRunsMillis = 3600000
//set to something smaller than 'wait_timeout'
minEvictableIdleTimeMillis = 18000000
//if you don't mind a hit for every getConnection(), set to "true"
testOnBorrow = "true"
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
其他方案(不推薦)
對於 MySQL5 之前的版本,如 Mysql4.x,只需要修改連接池配置中的 URL,添加一個參數:autoReconnect=true(如jdbc:mysql://hostaddress:3306/schemaname?autoReconnect=true),如果是 MySQL5 及以后的版本,則需要修改 my.cnf(或者my.ini) 文件,在 [mysqld]后面添加上:
wait_timeout = n
interactive-timeout = n
|
其中 n 為服務器關閉交互式連接前等待活動的秒數。可是就部署而言每次修改 my.ini 比較麻煩,而且 n 等於多少才是合適的值呢? 所以並不推薦這個解決辦法。)
原文地址:http://www.cnblogs.com/hemingwang0902/archive/2012/03/15/2397620.html
附件:
三大連接池的參數說明
1. Apache-DBCP
? BasicDataSource 相關的參數說明
- dataSource: 要連接的 datasource (通常我們不會定義在 server.xml)
- defaultAutoCommit: 對於事務是否 autoCommit, 默認值為 true
- defaultReadOnly: 對於數據庫是否只能讀取, 默認值為 false
- driverClassName:連接數據庫所用的 JDBC Driver Class,
- maxActive: 可以從對象池中取出的對象最大個數,為0則表示沒有限制,默認為8
- maxIdle: 最大等待連接中的數量,設 0 為沒有限制 (對象池中對象最大個數)
- minIdle:對象池中對象最小個數
- maxWait: 最大等待秒數, 單位為 ms, 超過時間會丟出錯誤信息
- password: 登陸數據庫所用的密碼
- url: 連接數據庫的 URL
- username: 登陸數據庫所用的帳號
- validationQuery: 驗證連接是否成功, SQL SELECT 指令至少要返回一行
- removeAbandoned: 是否自我中斷, 默認是 false
- removeAbandonedTimeout: 幾秒后會自我中斷, removeAbandoned 必須為 true
- logAbandoned: 是否記錄中斷事件, 默認為 false
- minEvictableIdleTimeMillis:大於0 ,進行連接空閑時間判斷,或為0,對空閑的連接不進行驗證;默認30分鍾
- timeBetweenEvictionRunsMillis:失效檢查線程運行時間間隔,如果小於等於0,不會啟動檢查線程,默認-1
- testOnBorrow:取得對象時是否進行驗證,檢查對象是否有效,默認為false
- testOnReturn:返回對象時是否進行驗證,檢查對象是否有效,默認為false
- testWhileIdle:空閑時是否進行驗證,檢查對象是否有效,默認為false
? 在使用DBCP的時候,如果使用默認值,則數據庫連接因為某種原因斷掉后,再從連接池中取得連接又不進行驗證,這時取得的連接實際上就會是無效的數據庫連接。因此為了防止獲得的數據庫連接失效,在使用的時候最好保證:
- username: 登陸數據庫所用的帳號
- validationQuery:SELECT COUNT(*) FROM DUAL
- testOnBorrow、testOnReturn、testWhileIdle:最好都設為true
- minEvictableIdleTimeMillis:大於0 ,進行連接空閑時間判斷,或為0,對空閑的連接不進行驗證
- timeBetweenEvictionRunsMillis:失效檢查線程運行時間間隔,如果小於等於0,不會啟動檢查線程
? PS:在構造GenericObjectPool [BasicDataSource在其createDataSource () 方法中也會使用GenericObjectPool] 時,會生成一個內嵌類Evictor,實現自Runnable接口。如果timeBetweenEvictionRunsMillis大於0,每過timeBetweenEvictionRunsMillis毫秒Evictor會調用evict()方法,檢查對象的閑置時間是否大於 minEvictableIdleTimeMillis毫秒(_minEvictableIdleTimeMillis小於等於0時則忽略,默認為30分鍾),是則銷毀此對象,否則就激活並校驗對象,然后調用ensureMinIdle方法檢查確保池中對象個數不小於_minIdle。在調用returnObject方法把對象放回對象池,首先檢查該對象是否有效,然后調用PoolableObjectFactory 的passivateObject方法使對象處於非活動狀態。再檢查對象池中對象個數是否小於maxIdle,是則可以把此對象放回對象池,否則銷毀此對象
? 上述特性的可設置性已在代碼中驗證,具體性能是否能實現有待實際驗證
2. C3P0
? C3P0的官方example中使用的數據源為ComboPooledDataSource,網上一篇文章詳細介紹了C3P0連接池配置中各項含義[這些配置項的含義在下載解壓c3p0的壓縮包之后目錄的doc\index.html中的Configuration部分也有詳細的介紹,這里偷下懶:P],現摘錄如下:
3
30
1000
false
Test
">false
100
e">
null
nsactions">false
">60
3
60
15
100
on">
3
root
password
select id from test where id=1
300
">false
true
root
eProxies">false
con_test
30000
">30
10
30
25
10
0
200
300
? 上述特性的可設置性已在代碼中驗證,具體性能是否能實現有待實際驗證
? 從配置項的內容來看,C3P0和DBCP都有比較詳細的有關連接檢測保證的配置,我們可以看到C3P0可以控制數據源內加載的PreparedStatements數量,並且可以設置幫助線程的數量來提升JDBC操作的速度,這些是DBCP未提供的;另外從網絡上的評價來看,DBCP出現Bug的頻率要大於C3P0,不過這一點有待於我們自己實際的檢測。
3. Proxool
? Proxool的使用和dbcp以及c3p0稍有不同,我們需要並且只需要在使用基本的java.sql.DriverManager之前加載org.logicalcobwebs.proxool.ProxoolDriver驅動類,並且按照proxool定義的url格式 ["proxool." + alias + ":" + driverClass + ":" + driverUrl ,其中alias是為連接池自定義的別名] 來獲得connection;具體的可以參看proxool doc下的UserGuide,或本文所附的示例代碼。下面對連接池的特性配置作詳細說明 [這個是自己翻譯的,不一定准確,有問題時請參看doc下的Properties ~]。
n fatal-sql-exception
以逗號隔開的異常列表,當設置了此項之后,每當出現SQLException時都將與列表中異常項作比較,如果匹配則認為出現fatal異常,這將導致connection被丟棄,並且不論出現任何情況該異常將被重拋一次以通知用戶發生的情況。默認值為null
n fatal-sql-exception-wrapper-class
如果配置了fatal-sql-exception,則默認的操作是丟 棄引起SQLException的原因而只是拋出原始異常。使用fatal-sql-exception-wrapper-class這個特性可以將 SQLException包裝到繼承SQLException或RunTimeException的任何異常類里。Proxool提供了兩個類供使用 FatalSQLException和FatalRunTimeException;使用這兩個類的話就將該選項設置為 'org.logicalcobwebs.proxool.FatalSQLException'或者 'org.logicalcobwebs.proxool.FatalRuntimeException'。默認值為null
n house-keeping-sleep-time
proxool自動偵察各個連接狀態的時間間隔(毫秒),偵察到空閑的連接就馬上回收,超時的銷毀,默認值為30秒
n house-keeping-test-sql
如果偵察線程發現閑置連接,則會使用這個SQL語句來對這些連接進行檢查;這項設置的語句應該能夠被很快的執行,例如查詢當前時間 [info.setProperty("proxool.house-keeping-test-sql", "select CURRENT_DATE");] 。如果不設置則該選項被忽略
n injectable-connection-interface、injectable-statement-interface、injectable-prepared-statement-interface、injectable-callable-statement-interface
n jmx
如果此項設為true,則連接池將被以名稱"Proxool:type=Pool, name="注冊為JMS Server的MBean。默認值為false
n jmx-agent-id
當且僅當jmx選項設為true時使用,為以逗號分隔的連接持注冊到的JMS代理名稱列表;如果不設置則所有注冊的JMX Server都將被使用
n maximum-active-time
線程最大存活時間,超過此時間的線程將被守護線程kill掉,默認值為5分鍾
n maximum-connection-count
到數據庫的最大連接數,超過了這個連接,再有請求時,就排在隊列中等候,最大的等待請求數由simultaneous-build-throttle決定;默認值為15
n maximum-connection-lifetime
連接最大存活時間,毫秒為單位,默認值為4小時
n minimum-connection-count
不管是否被使用都保持開放的最小連接數,默認值為5
n overload-without-refusal-lifetime
用來判斷連接池狀態,如果在此選項設置時間內(毫秒為單位)拒絕了連接,則認為過負載。默認值為60秒
n prototype-count
最少保持的空閑連接數,注意與minimum-connection-count區分。默認值為0
n simultaneous-build-throttle
最大的等待請求數,默認值為10
n test-before-use
如果設為true則connection在使用前將以house-keeping-test-sql設置的語句測試,如果測試不通過則該connection被丟棄並會重新分配一個connection。默認為false
n test-after-use
如果設為true則connection在關閉(放回連接池)前將以house-keeping-test-sql設置的語句測試,如果測試不通過connection將被丟棄。默認值為false
? 與其它連接池特性的設置方法不同,Proxool不提供相應的set方法,所有特性都要以諸如info.setProperty("proxool.jmx", "false");方式設定
? 上述特性的可設置性已在代碼中驗證,具體性能是否能實現有待實際驗證
原文地址:http://zhangsha1251.blog.163.com/blog/static/62624053201182111921783/