www.MyException.Cn 發佈於:2013-07-16 22:38:05 瀏覽:253次html
0java
myBatis鏈接MySQL報異常:No operations allowed after connection closed.Connection was imysql
?linux
org.hibernate.exception.JDBCConnectionException: could not execute querysql at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:74)數據庫 at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)apache .......tomcat 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 **less 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種:
固然最好的辦法是同時綜合使用上述3種方法,下面就 DBCP、C3P0 和 simple jdbc dataSource 分別作一說明,假設 wait_timeout 爲默認的8小時
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"
//獲取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
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 等於多少纔是合適的值呢? 因此並不推薦這個解決辦法。)
-------------------------相關-------------------------
1. 即便在建立Mysql時url中加入了autoReconnect=true參數,一但這個鏈接兩次訪問數據庫的時間超出了服務器端wait_timeout的時間限制,仍是會CommunicationsException: The last packet successfully received from the server was xxx milliseconds ago.
2. 服務器端的參數能夠用
show global variables like 'wait_timeout';
set global wait_timeout=10;
來進行設置,可是wait_timeout值不該該設的過高.
3. 較好的策略是對處於idle狀態的connection定時發送一個sql,來刷新服務器上的時間戳.這可使用c3p0r的鏈接池.http://bzhang.iteye.com/blog/321832
4. 對於tomcat的server.xml中使用的鏈接池,http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html,http://commons.apache.org/dbcp/configuration.html使用DBCP的鏈接池能夠採用
<Resource name="jdbc/test" auth="Container"
type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"
username="root" password="test" maxActive="500" maxIdle="10"
maxWait="-1" timeBetweenEvictionRunsMillis="10000" minEvictableIdleTimeMillis="10000" />
4.1 設置validationQuery,這樣每次borrow(默認爲開啓)時會經過這個sql校驗鏈接的有效性,可是增長了時間.
4.2 設置timeBetweenEvictionRunsMillis="10000" minEvictableIdleTimeMillis="10000" 依賴evictor thread線程來把超時的鏈接關閉.
4.3 設置testWhileIdle="true" timeBetweenEvictionRunsMillis="10000" validationQuery="select 1" 使得定時去用query檢測處於idle狀態的鏈接,也就刷新了服務器端的時間.
5.每次提交的最大packet大小
show global variables like 'max_allowed_packet';
set global max_allowed_packet=1024*1024;
6. SQLyog 中鏈接參數的設置
6.1 在SQLyog中的設置 set autocommit=0,這樣當前鏈接的自動提交爲false,能夠控制事務了.
6.2 begin; 事務開始
6.3 select * from test where 1=1 and id =1 for update;這樣就把選到的記錄行鎖上了,再開一個SQLyog,也執行以上相同的操做,就會一直wait在那裏.
6.4 commit; 提交
6.5 rollback; 回滾
6.6 set autocommit=0;後應該加上
set transaction isolation level read committed;
這樣其它客戶端就能看到commit的數據,
疑問:
若是不設置set transaction isolation level read committed;若是兩個客戶端都select 相同的數據,一個客戶端修改而後提交,另外一個客戶端不提交當前事務的前提下,去執行select ,取不到另外一客戶端提交的數據,不知道SQLyog默認的事務級別是什麼樣的.
7. SQLyog中查看mysql的狀態,show global variables like '%lock%'; 是個好方法.對於事務鎖(例如for update)報Lock wait timeout exceeded ,只能經過修改my.ini文件innodb_lock_wait_timeout = 100;才能生效.
8. linux下修改用戶密碼 mysqladmin -u root password "new_pass"
後續有不少開發填坑的文章發佈,若是對你有幫助,請支持和加關注一下