在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