萬盛學電腦網

 萬盛學電腦網 >> 數據庫 >> mysql教程 >> 連接MySql超時斷開報錯問題

連接MySql超時斷開報錯問題

   使用Mysql數據庫時,最讓人頭疼的一個問題就是不定時會出現連接報錯異常Exception,類似的Exception如下(Hibernate為例):
?

1 2 3 4 5 6 7 8 9 10 org.hibernate.util.JDBCExceptionReporter - SQL Error:0, SQLState: 08S01 org.hibernate.util.JDBCExceptionReporter - The last packet successfully received from the server was43200 milliseconds ago.The last packet sent successfully to the server was 43200 milliseconds ago, which is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection 'autoReconnect=true' to avoid this problem. org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session org.hibernate.exception.JDBCConnectionException: Could not execute JDBC batch update com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Connection.close() has already been called. Invalid operation in this state. org.hibernate.util.JDBCExceptionReporter - SQL Error:0, SQLState: 08003 org.hibernate.util.JDBCExceptionReporter - No operations allowed after connection closed. Connection was implicitly closed due to underlying exception/error:   ** BEGIN NESTED EXCEPTION ** com.mysql.jdbc.exceptions.jdbc4.CommunicationsException

  大多數人遇到這個問題都會很費解,我也是遇到這個問題,細細研究後才發現了本質原因。

  一、問題原因

  Mysql的配置中,有一個叫做“wait_timeout"的參數,這個參數大致的意思是這樣:當一個客戶端連接到MySQL數據庫後,如果客戶端不自己斷開連接,也不做任何操作,MySQL數據庫會將這個連接保留"wait_timeout"這麼長時間(單位是s,默認是28800s,也就是8小時),超過這個時間之後,MySQL數據庫為了節省資源,就會在數據庫端斷開這個連接;當然,在此"wait_timeout"過程中,如果客戶端在這個連接上有任意的操作,MySQL數據庫都會重新開始計算這個時間。

  這麼看來,發生連接異常Exception的原因就是因為我們的程序和MySQL數據庫的連接超過了”wait_timeout"時間,Mysql服務器端將其斷開了,但是我們的程序再次使用這個連接時沒有做任何判斷,所以就掛了。

  那如何解決這個問題呢?

  二、解決方法

  1. 延長Mysql配置中wait_timeout參數的數值。

  我看有的人直接就延長到一年了,也有人說這個值最大也就是21天,即使值設的再大,MySQL也就只識別21天(這個我沒有具體去MySQL的文檔中去查)。但是這是一個治標不治本的方法,即使可以一年,也還是會有斷的時候,服務器可是要7x24小時在線的。

  2. 在進行數據庫操作之前,進行“check”檢查機制(即檢查連接是否有效)

  這裡其實有好多種方案,Hibernate本身有配置方法,各個連接池(c3p0等)也有配置方法,這裡我們以c3p0的Hibernate配置為例。

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <session-factory>     <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>     <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>     <property name="hibernate.connection.useUnicode">true</property>     <property name="hibernate.connection.characterEncoding">UTF-8</property>     <property name="hibernate.show_sql">true</property>     <!-- c3p0在我們使用的Hibernate版本中自帶,不用下載,直接使用 -->     <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>     <property name="hibernate.c3p0.min_size">5</property>     <property name="hibernate.c3p0.max_size">20</property>     <property name="hibernate.c3p0.timeout">1800</property>     <property name="hibernate.c3p0.max_statements">50</property>     <!-- 下面這句很重要,後面有解釋 -->     <property name="hibernate.c3p0.testConnectionOnCheckout">true</property>     <!-- 以下就全是mapping了,省略 --> </session-factory>

  上面配置中最重要的就是hibernate.c3p0.testConnectionOnCheckout這個屬性,它保證了我們前面說的每次取出連接時會檢查該連接是否被關閉了。不過這個屬性會對性能有一些損耗,也可以采用其他方法。

  其實還有很多種方法可以實現"check"機制,大家有興趣可以多多了解相關知識。c3p0也可以不用testConnectionOnCheckout而用select 1等方法。

copyright © 萬盛學電腦網 all rights reserved