最近獨自寫了個小項目,測試的時候都OK,放到服務器後發現隔天便會出現Error:org.hibernate.exception.JDBCConnectionException: could not execute query,幾經觀察,確認是數據庫連接池出了問題,查了些資料,找到了解決方法:
MySQL對所有連接的有效時間默認為28800秒,正好8小時,也就是說,如果一個連接8小時沒有請求和操作,就會自動斷開;但是對於Hibernate來說,它的連接池並不知道它所管理的連接中是否有被MySQL斷開的。如果一個程序要使用數據庫連接,而Hibernte的連接池分配一個已經被MySQL斷開了的給程序使用,那么便會出現錯誤。
為了證實確實是這個錯誤,我在本機上做了如下測試:首先啟動Tomcat,網站能夠正常打開;然后修改系統時間,往后調1天;然后再打開網站,同樣的問題果然出現!MySQL + Hibernate架構相當普遍,所以這個問題也相當普遍,若讀者也有這樣的項目,建議做一下同樣的測試,看看是否存在此問題!
問題找到了,怎么解決呢?
思路1:增大MySQL的連接有效時間;
思路2:從程序自身出發,修改連接池的相關參數。
顯然,思路1是不可行的,一方面這個思路不可能保證這個問題絕對的解決,如果無訪問時間夠長,還是大於MySQL的連接有效時間,問題同樣會發生;另一方面,一般情況下,我們都是將程序部署在別人服務器上,我們不可能去修改MySQL配置。那么只能從思路2入手了。
經查資料發現,Hibernate支持如下的連接池:
DriverManagerConnectionProvider:代表由Hibernate提供的默認的數據庫連接池
C3P0ConnectionProvider:代表C3P0連接池
ProxoolConnectionProvider:代表Proxool連接池
DBCPConnectionProvider:代表DBCP連接池
DatasourceConnectionProvider:代表在受管理環境中由容器提供的數據源
其中,默認連接池並不支持在分配一個連接時,測試其有效與否的功能,而C3P0、Proxool、DBCP都提供了這樣的功能,正好可以解決上述問題。綜合考慮各個連接池的效率、穩定性、易用性,決定換用Proxool,它確實在各方面表現優良,方便配置。
下面就看看如何配置Proxool:
1、Hibernate配置文件:
<session-factory>
<property name=”hibernate.connection.provider_class”>org.hibernate.connection.ProxoolConnectionProvider</property>
<property name=”hibernate.proxool.xml”>proxool.xml</property>
<property name=”hibernate.proxool.pool_alias”>mysql</property>
<property name=”show_sql”>false</property>
<property name=”dialect”>org.hibernate.dialect.MySQLDialect</property>
<mapping resource=”com/lab1000/jcom/pojo/Admin.hbm.xml” />
…
</session-factory>
其中各屬性含義如下:
hibernate.connection.provider_class:指明使用Proxool連接池
hibernate.proxool.xml:指明Proxool配置文件所在位置,這里與Hibernate的配置文件在同一目錄下
hibernate.proxool.pool_alias:指明要使用的proxool.xml中定義的proxool別名。
2、Proxool配置文件(proxool.xml):
<?xml version=”1.0″ encoding=”UTF-8″?>
<!– the proxool configuration can be embedded within your own application’s.
Anything outside the “proxool” tag is ignored. –>
<something-else-entirely>
<proxool>
<!– proxool別名 –>
<alias>mysql</alias>
<!– 數據庫連接Url –>
<driver-url>
jdbc:mysql://localhost/yourDatebase?useUnicode=true&characterEncoding=UTF-8
</driver-url>
<!– JDBC驅動名稱 –>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<!– 數據庫連接帳號 –>
<driver-properties>
<property name=”user” value=”root” />
<property name=”password” value=”password” />
</driver-properties>
<!– proxool自動偵察各個連接狀態的時間間隔(毫秒),偵察到空閑的連接就馬上回收,超時的銷毀 –>
<house-keeping-sleep-time>90000</house-keeping-sleep-time>
<!– 指因未有空閑連接可以分配而在隊列中等候的最大請求數,超過這個請求數的用戶連接就不會被接受 –>
<maximum-new-connections>20</maximum-new-connections>
<!– 最少保持的空閑連接數 –>
<prototype-count>3</prototype-count>
<!– 允許最大連接數,超過了這個連接,再有請求時,就排在隊列中等候,最大的等待請求數由maximum-new-connections決定 –>
<maximum-connection-count>20</maximum-connection-count>
<!– 最小連接數 –>
<minimum-connection-count>3</minimum-connection-count>
<!– 在分配連接前后是否進行有效性測試,這個是解決本問題的關鍵 –>
<test-before-use>true</test-before-use>
<test-after-use>true</test-after-use>
<!– 用於測試的SQL語句 一定要寫(不知道問什么)–>
<house-keeping-test-sql>SELECT CURRENT_USER</house-keeping-test-sql>
</proxool>
</something-else-entirely>
3、下載和安裝Proxool的包文件
下載地址:http://proxool.sourceforge.net/download.html
下載后並解壓后,將其中lib文件夾下的jar文件拷貝到你站點的WEB-INF/lib下
自此,Proxool配置成功。重新啟動Tomcat,再次做上述測試,問題解決。
此外,如果要使用C3P0或DHCP,可以參考以下資料:
http://blog.csdn.net/lip8654/archive/2008/02/26/2121387.aspx
http://azi.javaeye.com/blog/182146
http://fishyych.javaeye.com/blog/90793