问题剖析

     mysql的默认最大timeout时间是8小时,对空闲超过8小时的数据库连接会强行断开。

      timeout有两种,一个是非交互式的最大等待时间wait_timeout,另一个是交互式的最大等待时间interactive_time,交互连接如mysql gui tool中的连接。一般情况下interactive_timeout的设置将要对你的web 应用没有多大的影响。wait_timeout的时间设置太小话会导致连接关闭很快,从而使一些持久连接不起作用,反之设置过大,容易造成连接打开时间过长,在show processlist时,能看到太多的sleep状态的连接,从而造成too many connections错误。

  用 show variables like'%timeout%';命令查看wait_timeout

       

     可以看出默认为(60*60*8)28800毫秒,也就是8小时。


mysql/my.cnf 文件,在 [mysqld] 节中设置:




# Set a connection to wait  
 8  
 hours in idle status. 
 
      wait_timeout = 86400


或直接命令设置  set wait_timeout=86400;   将时间超时设置为24小时,但时间越长可能产生的长时间闲置的连接数就越多造成时间的浪费。


当然,该事件不能无限大本人试过最大为2147483,大概24天多。




解决方案一:


连接数据库的时候加上autoReconnect=true这个参数:

jdbc:mysql://localhost:3306/accounant?useUnicode=true&characterEncoding=UTF-8&  autoReconnect=true


但是,在mysql手册中有这样一段话:

       autoReconnect

驱动程序是否应尝试再次建立失效的和/或死连接? 如果允许,对于在失效或死连接上发出的查询(属于当前事务),驱动程序将抛出异常,但在新事务的连接上发出下一个查询时,将尝试再连接。不推荐使用该特性,这是因为,当应用程序不能恰当处理SQLExceptions时,它会造成与会话状态和数据一致性有关的副作用,设计它的目的仅用于下述情况,即,当你无法配置应用程序来恰当处理因死连接和/或无效连接导致的SQLExceptions时。作为可选方式,可将MySQL服务器变量“wait_timeout”设置为较高的值,而不是默认的8小时。 

注:网上所说的 设置 "autoReconnect=true" 的方法,只有mysql4以前的版本才适用......


        解决方案二


       

程序中配置处理死连接或无效连接

下面是实际应用中,在数据源控制闲置连接的方法。


DBCP数据源中配置


 方法一

</property>
 
  <property name="testOnBorrow"> <value>true</value></property>


  testOnBorrow指明是否在从池中取出连接时进行检验,检验失败,则从池中去除该连接,并尝试取出新的连接,不会出现8小时问题。但在高并发的应用中将会带来性能问题,因为他会需要更多地数据库访问请求。


方法二

<property name="validationQuery"> <value>select 1</value></property> 

 
  <property name="testOnBorrow">   <value>false</value> 
 </property> 
 
 

     <property name="minEvictableIdleTemeMillis"><value>60000</value></property> 

 

     <property name="timeBetweenEvictionRunsMills"><value>10000</value></property>


解释


 validationQuery SQL查询,用来验证从连接池取出的连接,在将连接返回给调用者之前.如果指定,则查询必须是一个SQL SELECT并且必须返回至少一行记录。 


1000 * 60 * 30 30分


timeBetweenEvictionRunsMillis  在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位.如果设置为非正数,则不运行空闲连接回收器线程


数据库重启后minEvictableIdleTimeMillis毫秒前访问web应用,连接数据库使用的还是连接池中老的连接,所以还会出现上述的错误,timeBetweenEvictionRunsMillis和minEvictableIdleTimeMillis也不宜设置过小,会加重系统开销。


注意:两个时间之和要小于mysql的wait_timeout时间,避免因为时间差,闲置连接已经被mysql断开却没被线程回收。


方法三


<property name="validationQuery"> <value>select 1</value></property>
 
<property name="testOnBorrow"> <value>false</value></property>
 
<property name="testWhileIdle"> <value>true</value></property>
 
<property name="timeBetweenEvictionRunsMills"><value>10000</value></property>


testWhileIdle 指明连接是否被控线连接回收器(如果有)进行检验。检验失败,则连接将被从池中去除。


原理,同方法二。


C3P0数据源中配置

1. <bean id="dataSource"  
2. class="com.mchange.v2.c3p0.ComboPooledDataSource">  
3. <property name="preferredTestQuery"  
4. value="select 1" />  
5. <property name="maxIdleTime" 
6. value="25200" /> 
7. <property name="idleConnectionTestPeriod"  
8. value="18000" />  
9. <property name="testConnectionOnCheckout"  
10. value="ture" />  
11. <!-- other properties -->  
12. </bean>


以上是小弟近日对mySql 8小时问题的总结,如有误导之处,望纠正,一起进步。