使用Mysql數據庫時,最讓人頭疼的一個問題就是不定時會出現連接報錯異常Exception,類似的Exception如下(Hibernate為例):
?
大多數人遇到這個問題都會很費解,我也是遇到這個問題,細細研究後才發現了本質原因。
一、問題原因
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等方法。