java+jsp+server 2010-07-27 09:10:38 閱讀330 評論4 字號:大中小 訂閱
數(shù)據(jù)庫連接出錯信息有下面兩條:
com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: No operations allowed after connection closed.Connection was implicitly closed due to underlying exception/error:
com.mysql.jdbc.CommunicationsException: Communications link failure
================分割線================
一直想不出什么原因?qū)е拢W(wǎng)上查資料也不順利,后來找到了hibernate連接數(shù)據(jù)庫,產(chǎn)生同樣的錯誤時的處理方法,知道了問題出在哪里:
com.mysql.jdbc.CommunicationsException: Communications link failure due to underlying exception:
查看了Mysql的文檔,以及Connector/J的文檔以及在線說明發(fā)現(xiàn),出現(xiàn)這種異常的原因是:Mysql服務(wù)器默認(rèn)的“wait_timeout”是8小時,也就是說一個connection空閑超過8個小時,Mysql將自動斷開該 connection。這就是問題的所在,在C3P0 pools中的connections如果空閑超過8小時,Mysql將其斷開,而C3P0并不知道該connection已經(jīng)失效,如果這時有 Client請求connection,C3P0將該失效的Connection提供給Client,將會造成上面的異常。
上網(wǎng)搜索,在MySQL的論壇上找到一個辦法,就是如果在執(zhí)行sql語句的時候發(fā)生了上述異常,就將sql語句重新執(zhí)行一次。
試驗發(fā)現(xiàn),這個辦法對這個使用spring+hibernate的服務(wù)無效。
進一步搜索發(fā)現(xiàn),MySQL官方不推薦使用autoReconnect=true,參見http://bugs.mysql.com/bug.php?id=5020
需要另外找別的辦法來解決這個問題。
由于問題產(chǎn)生的根本原因在于服務(wù)到數(shù)據(jù)庫的連接長時間沒活動,既然重新連接的辦法無效,就可以嘗試另外一種辦法,就是反空閑。
自己寫一個線程來反空閑的話,比較麻煩。
最后在網(wǎng)上找到一個辦法。為hibernate配置連接池,推薦用c3p0,然后配置c3p0的反空閑設(shè)置idle_test_period,只要小于MySQL的wait timeout即可。
在hibernate.cfg.xml中增加下面幾項:
<!-- configuration pool via c3p0-->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="c3p0.min_size">5</property>
<property name="c3p0.max_size">30</property>
<property name="c3p0.time_out">1800</property> <!-- seconds --><!-- default: 0 -->
<property name="c3p0.max_statement">50</property> <!-- default: 0 -->
<property name="c3p0.acquire_increment">1</property> <!-- default: 1 -->
<property name="c3p0.idle_test_period">120</property> <!-- seconds --><!-- default: 0 -->
<property name="c3p0.validate">true</property>
修改完后測試,問題解決。
================分割線================
具體修改方法如下:
對于MySQL5之前的版本,如Mysql4.x,只需要修改連接池配置中的URL,添加一個參數(shù):autoReconnect=true(如jdbc:mysql://hostaddress:3306/schemaname?autoReconnect=true),如果是MySQL5及以后的版本,則需要修改my.cnf(或者my.ini)文件,在[mysqld]后面添加上:
wait_timeout = n
interactive-timeout = n
(n為服務(wù)器關(guān)閉交互式連接前等待活動的秒數(shù)??墒蔷筒渴鸲悦看涡薷膍y.ini比較麻煩,而且n等于多少才是合適的呢?所以這個解決辦法不好。)
查ibatis文檔后修改如下,紅字部分是修改的重點:
<transactionManager type="JDBC">
<dataSource type="SIMPLE">
<property name="JDBC.Driver" value="com.mysql.jdbc.Driver" />
<property name="JDBC.ConnectionURL"
value="jdbc:mysql://192.168.1.4:3306/mail?characterEncoding=utf-8" />
<property name="JDBC.Username" value="abc" />
<property name="JDBC.Password" value="abc" />
<property name="Pool.MaximumActiveConnections" value="10" />
<property name="Pool.MaximumIdleConnections" value="5" />
<property name="Pool.MaximumCheckoutTime" value="120000" />
<property name="Pool.TimeToWait" value="500" />
<property name="Pool.PingQuery" value="select 1 from redirect_url" />
<property name="Pool.PingEnabled" value="true" />
<property name="Pool.PingConnectionsOlderThan" value="0" />
<property name="Pool.PingConnectionsNotUsedFor" value="3600000" /><!-- 對于空閑的連接一個小時檢查一次 -->
</dataSource>
</transactionManager>