解決MySql數據庫鏈接超時問題

在Mysql的默認設置中,若是一個數據庫鏈接超過8小時沒有使用(閒置8小時,即28800s),mysql server將主動斷開這條鏈接。 在此輸入圖片描述html

在運維監控系統中,程序會報以下異常:java

<!-- lang: java -->
org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on     Hibernate data access; nested exception is org.hibernate.exception.GenericJDBCException: could not inspect JDBC autocommit mode

底層錯誤日誌:mysql

<!-- lang: java -->
    [130925-102435-381][ERROR][ActionQueue:afterTransactionCompletion 179]could not release a cache lock
org.hibernate.cache.CacheException: java.lang.IllegalStateException: The org.hibernate.cache.UpdateTimestampsCache Cache is not alive.
	at org.hibernate.cache.EhCache.put(EhCache.java:125)
	at org.hibernate.cache.UpdateTimestampsCache.invalidate(UpdateTimestampsCache.java:69)
	at org.hibernate.engine.ActionQueue.afterTransactionCompletion(ActionQueue.java:174)
	at org.hibernate.impl.SessionImpl.afterTransactionCompletion(SessionImpl.java:424)
	at org.hibernate.jdbc.JDBCContext.afterTransactionCompletion(JDBCContext.java:225)
	at org.hibernate.transaction.JDBCTransaction.rollback(JDBCTransaction.java:174)
	at org.springframework.orm.hibernate3.HibernateTransactionManager.doRollback(HibernateTransactionManager.java:577)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:631)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:608)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:328)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:111)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
	at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:652)
	at com.sinosoft.sepmis.inspection.service.InspectionDataServiceImpl$$EnhancerByCGLIB$$d9f54f39.saveInspectionData(<generated>)
	at com.sinosoft.sepmis.util.ConnectionTelnet.execute(ConnectionTelnet.java:319)
	at com.sinosoft.sepmis.util.InspectionUtil.inspectExecute(InspectionUtil.java:331)
	at com.sinosoft.sepmis.util.InspectionUtil.partOfManual(InspectionUtil.java:259)
	at com.sinosoft.sepmis.util.ThreadManageUtil.startInspect(ThreadManageUtil.java:45)
	at com.sinosoft.sepmis.util.ThreadManageUtil.run(ThreadManageUtil.java:31)
	at java.lang.Thread.run(Thread.java:735)
Caused by: 
java.lang.IllegalStateException: The org.hibernate.cache.UpdateTimestampsCache Cache is not alive.
	at net.sf.ehcache.Cache.checkStatus(Cache.java:1204)
	at net.sf.ehcache.Cache.put(Cache.java:549)
	at net.sf.ehcache.Cache.put(Cache.java:522)
	at org.hibernate.cache.EhCache.put(EhCache.java:119)
	... 19 more

緣由分析:spring

因爲程序後臺一直在運行定時程序,並且定時程序的運行爲7*24小時。在這期間程序會出現八小時閒置的狀況,即程序和數據庫之間沒有任何交換操做。這樣Mysql數據庫端會主動動斷開鏈接。這樣若是定時啓動後,要想獲取到Mysql的鏈接,天然就會報出異常。sql

方法一,Mysql數據庫延長wait_timeout參數時間(不推薦):數據庫

經過修改my.ini(Linux系統爲my.cnf)文件中wait_timeout=xxx,即使是這樣系統在閒着超過此參數設置時間後依然會出現異常。(注意:此參數單位爲秒) 也能夠經過mysql命令設置。api

<!-- lang: sql -->
Mysql > set global wait_timeout=xxx;

設置後重啓mysql服務,命令以下: <!-- lang: sql --> service mysql restart 登陸mysql查看是否生效: <!-- lang: sql --> Mysql > show global variables like 'wait_timeout'; 在此輸入圖片描述運維

方法二,修改hibernate 中配置屬性(不推薦):性能

代碼以下測試

<!-- lang: xml -->
<property name="connection.autoReconnect">true</ property>
<property name="connection.autoReconnectForPools">true</ property >
<property name="connection.is-connection-validation-required">true</ property>

我的經過試驗發現,這種方法並無起到效果。不知道網上的寫文章的人是怎麼解決的。

方法三,使用第三方數據庫鏈接池(推薦): 如今第三方數據庫鏈接池使用較多的爲c3p0,proxool等,在性能上c3p0稍好一些,緣由c3p0數據庫鏈接池,底層有一個定時查看數據庫鏈接是否有效的參數。並且Hibernate的api中也推薦使用第三方數據庫鏈接池,由於Hibernate自己的數據庫鏈接池過於簡單、自己存在bug。c3p0參數配置以下:

<!-- lang: xml -->
<!-- 數據源 --> 
<bean id="dataSourceTarget" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="user" value="root" />
<property name="password" value="root" />
<property name="jdbcUrl" value="jdbc:mysql://192.168.61.208:3306/sinoomv1_0_0" />
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<!-- 系統初始化鏈接數 -->
<property name="initialPoolSize" value="10" />
<!-- 最大鏈接數 -->
<property name="maxPoolSize" value="30" />
<!-- 最小鏈接數 -->
<property name="minPoolSize" value="10" />
<!--最大空閒時間,600秒(10分鐘)內未使用則鏈接被丟棄。若爲0則永不丟棄。Default: 0 -->
<property name="maxIdleTime" value="600" />
<!--當鏈接池中的鏈接耗盡的時候c3p0一次同時獲取的鏈接數。Default: 3 -->  
<property name="acquireIncrement" value="3" />
<!--每60秒檢查全部鏈接池中的空閒鏈接。Default: 0 -->  
<property name="idleConnectionTestPeriod" value="60" />
<!-- 每次從pool內checkout鏈接時測試有效性(同步操做)
    程序每次數據庫調用都鏈接有效性,若無效關閉此鏈接並剔除出pool,
   從pool內取其餘鏈接,慎用,會形成至少多一倍的數據庫調用。Default:false -->
<property name="testConnectionOnCheckout" value="false" />
<!--定義在從數據庫獲取新鏈接失敗後重復嘗試的次數。Default: 30 -->
<property name="acquireRetryAttempts" value="30"/>
<!--兩次鏈接中間隔時間,單位毫秒。Default: 1000 -->
<property name="acquireRetryDelay" value="1000"/>
</bean>

查看mysql數據庫鏈接池狀況,命令以下:

<!-- lang: sql -->
Mysql> show processlist;

在此輸入圖片描述

ps:最近在在停起程序的時候我發現了一個問題,就算是我中止了服務,可是程序和mysql數據庫之間的鏈接數依然沒有斷開,後來經查資料和同事請教,我發如今上邊的c3p0配置存在一個小bug。由於我將c3p0交給Spring進行管理,可是在上邊注入的bean中沒有加上destroy-method="close"這個屬性。 也就是說Spring是不能正常銷燬鏈接的,由此出現了我說的問題。

寫在這裏以供你們警示,真是馬虎啊,居然忘記了銷燬,實在不該該。

<!-- lang: xml -->
<!-- 數據源 --> 
<bean id="dataSourceTarget" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
 ... ...
</bean>

參考文章:

Hibernate API 文檔 http://blog.csdn.net/nethibernate/article/details/6658855 http://zhidao.baidu.com/question/96746075.html

相關文章
相關標籤/搜索