Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure


很長的報錯,截取

 

  1.  
    ERROR c.a.d.p.DruidDataSource - discard connection
  2.  
    com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
  3.  
     
  4.  
    The last packet successfully received from the server was 44,866 milliseconds ago. The last packet sent successfully to the server was 0 milliseconds ago.
  5.  
    at sun.reflect.GeneratedConstructorAccessor103.newInstance(Unknown Source) ~[na:na]
  6.  
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java: 45) ~[na:1.7.0_79]
  7.  
    at java.lang.reflect.Constructor.newInstance(Constructor.java: 526) ~[na:1.7.0_79]
  8.  
    at com.mysql.jdbc.Util.handleNewInstance(Util.java: 404) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  9.  
    at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java: 981) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  10.  
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java: 3465) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  11.  
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java: 3365) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  12.  
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java: 3805) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  13.  
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java: 2478) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  14.  
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java: 2625) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  15.  
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java: 2551) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  16.  
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java: 1861) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  17.  
    at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java: 1962) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  18.  
    at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java: 227) ~[druid-1.0.5.jar:1.0.5]
  19.  
    at com.jfinal.plugin.activerecord.DbPro.query(DbPro.java: 73) [jfinal-2.2.jar:na]
  20.  
    at com.jfinal.plugin.activerecord.DbPro.query(DbPro.java: 100) [jfinal-2.2.jar:na]
  21.  
    at com.jfinal.plugin.activerecord.Db.query(Db.java: 47) [jfinal-2.2.jar:na]
  22.  
    ...
  23.  
     
  24.  
    Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
  25.  
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java: 2957) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  26.  
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java: 3375) ~[mysql-connector-java-5.1.38.jar:5.1.38]
  27.  
    ... 55 common frames omitted

 

 

參考鏈接:

http://blog.csdn.net/pandajava/article/details/41946251

http://blog.csdn.net/shiqidide/article/details/7642531

https://stackoverflow.com/questions/2983248/com-mysql-jdbc-exceptions-jdbc4-communicationsexception-communications-link-fai

 

 

起因和現象:

項目運行后,莫名其妙就在log中看到這個報錯,但是數據也能獲取到,不影響日常使用,但是看到了總歸不爽。

 

看了下網上的原因:

MySQL服務器默認的“wait_timeout”是28800秒即8小時,意味着如果一個連接的空閑時間超過8個小時,MySQL將自動斷開該連接,而連接池卻認為該連接還是有效的(因為並未校驗連接的有效性),當應用申請使用該連接時,就會導致上面的報錯。
出現異常”The last packet sent successfully to the server was 0 milliseconds ago.“的大部分原因


是由於數據庫回收了連接,而系統的緩沖池不知道,繼續使用被回收的連接所致的。


解決方法:

1.JDBC的URL中加上屬性(舊版本可用,不推薦)

按照錯誤的提示,可以在JDBC URL中使用autoReconnect屬性,實際測試時使用了autoReconnect=true&failOverReadOnly=false,不過並未起作用,
使用的是5.1版本,可能真像網上所說的只對4之前的版本有效。


2.修改MYSQL的配置文件my.ini/my.cnf,添加超時等待參數的最長時間(推薦)

沒辦法,只能修改MySQL的參數了,wait_timeout最大為31536000即1年,在my.cnf中加入:
[mysqld]
wait_timeout=86400 (1天)
interactive_timeout=7200
重啟生效,需要同時修改這兩個參數。

3.修改配置,讓緩沖池驗證鏈接是否有效

#SQL查詢,用來驗證從連接池取出的連接
dbcp.validationQuery=SELECT 1
#指明連接是否被空閑連接回收器(如果有)進行檢驗,如果檢測失敗,則連接將被從池中去除
dbcp.testWhileIdle=true
#在空閑連接回收器線程運行期間休眠的時間值,以毫秒為單位,一般比minEvictableIdleTimeMillis小
dbcp.timeBetweenEvictionRunsMillis=300000
#在每次空閑連接回收器線程(如果有)運行時檢查的連接數量,最好和maxActive一致
dbcp.numTestsPerEvictionRun=50
#連接池中連接,在時間段內一直空閑,被逐出連接池的時間(1000*60*60),以毫秒為單位
dbcp.minEvictableIdleTimeMillis=3600000

 

如果在wait_timeout秒期間內,數據庫連接(java.sql.Connection)一直處於等待狀態,mysql5就將該連接關閉。這時,你的Java應用的連接池仍然合法地持有該連接的引用。當用該連接來進行數據庫操作時,就碰到上述錯誤。這解釋了為什么我的程序第二天不能登錄 的問題。 

你可能會想到在tomcat的數據源配置中有沒有辦法解決?的確,在jdbc連接url的配置中,你可以附上“autoReconnect=true”,但這僅對mysql5以前的版本起作用。增加“validation query”似乎也無濟於事。 

原因分析

當數據庫重啟數據庫空閑連接超過設置的最大timemout時間,數據庫會強行斷開已有的鏈接,最大timeout時間可以通過命令show global variables like "wait_timeout";查詢:

mysql> show global variables like "wait_timeout"; +---------------+-------+ | VARIABLE_NAME | VALUE | +---------------+-------+ | wait_timeout | 28800 | +---------------+-------+ 1 row in set (0.00 sec)

解決辦法

為了解決這個異常,我們在配置數據庫連接池的時候需要做一些檢查連接有效性的配置,這里以Druid為例,相關配置如下(更多配置):

字段名 默認值 說明
validationQuery   用來檢測連接是否有效的sql,要求是一個查詢語句,常用select 'x'。如果validationQuery為null,testOnBorrow、testOnReturn、testWhileIdle都不會起作用。
validationQueryTimeout   單位:秒,檢測連接是否有效的超時時間。底層調用jdbc Statement對象的void setQueryTimeout(int seconds)方法
testOnBorrow true 申請連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能。
testOnReturn false 歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能。
testWhileIdle false 建議配置為true,不影響性能,並且保證安全性。申請連接的時候檢測,如果空閑時間大於timeBetweenEvictionRunsMillis,執行validationQuery檢測連接是否有效。
timeBetweenEvictionRunsMillis 1分鍾(1.0.14) 有兩個含義:1) Destroy線程會檢測連接的間隔時間,如果連接空閑時間大於等於minEvictableIdleTimeMillis則關閉物理連接。2) testWhileIdle的判斷依據,詳細看testWhileIdle屬性的說明

為了避免空閑時間過長超過最大空閑時間而被斷開,我們設置三個配置:

validationQuery: SELECT 1 testWhileIdle: true timeBetweenEvictionRunsMillis: 28000

其中timeBetweenEvictionRunsMillis需要小於mysql的wait_timeout

但是這種方法無法避免重啟的情況,不過一般數據庫不會頻繁重啟,影響不大,如果非得頻繁重啟,可以通過設置testOnBorrow,即申請連接的時候先試一試連接是否可用,不過帶來的影響就是性能降低,需要根據實際需求合理取舍。

 

 

 

轉自:

https://blog.csdn.net/tuntun1120/article/details/78866991


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM