在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