背景

最近做的一个JavaWeb项目,持久层用SpringJDBC+DBCP+MySQL。一开始只配置了DBCP的一些常用参数,没有注意对空闲连接的检查和回收。项目部署在tomcat后,刚开始使用没用问题。第二天再试图登录时,发生了报错:

HTTP Status 500 – Request processing failed; nested exception is org.springframework.dao.RecoverableDataAccessException: PreparedStatementCallback; SQL [select * from users where username = ? and password = ?]; The last packet successfully received from the server was 82,664,635 milliseconds ago. The last packet sent successfully to the server was 82,664,635 milliseconds ago. is longer than the server configured value of ‘wait_timeout’. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property ‘autoReconnect=true’ to avoid this problem.; nested exception is com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 82,664,635 milliseconds ago. The last packet sent successfully to the server was 82,664,635 milliseconds ago. is longer than the server configured value of ‘wait_timeout’. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property ‘autoReconnect=true’ to avoid this problem.

可以看到,报错信息提示上次交互已经是82664635ms前,超过了MySQL server配置的’wait_timeout'(默认是8小时),所以该连接已经被MySQL回收了,但DBCP不知道连接已被回收,依然试图执行操作,引发了异常。报错信息提示可以修改wait_timeout或者添加autoReconnect=true。
(备注:mysql5以上的,设置autoReconnect=true 是无效的 只有4.x版本,起作用)

解决办法

  1. 修改MySQL设置(不推荐)
    修改mysql安装目录下的配置文件 my.ini文件(如果没有此文件,复制“my-default.ini”文件,生成“复件 my-default.ini”文件。将“复件 my-default.ini”文件重命名成“my.ini” ),在文件中设置:
wait_timeout=31536000  
interactive_timeout=31536000

这两个参数的默认值是8小时(60608=28800)。 注意:wait_timeout的最大值只允许2147483 (24天左右)
也可以用MySQL命令进行修改

show variables like "%timeout%"
set interactive_timeout=31536000
set wait_timeout=31536000
修改wait_timeout

这种办法治标不治本。

2.减少连接池内连接的生存周期,使之小于上一项中所设置的wait_timeout 的值。
也就是说,让已经断开的空闲连接没有机会被使用,提前被回收。
以C3P0配置为例:

       
      
      
 

DBCP中配置minEvictableIdleTimeMillis即可。
3.配置连接池
定期使用连接池内的连接,使得它们不会因为闲置超时而被 MySQL 断开。并且每次使用连接前检查连接是否可用,定期回收空闲的连接。
修改 c3p0 的配置文件,在 Spring 的配置文件中设置:

  
      
      
      

DBCP连接池的配置:


DBCP官方配置文档:http://commons.apache.org/proper/commons-dbcp/configuration.html

其他参数就不多说了,针对连接池失效的几个重要参数做下说明。
1、testOnReturn,testOnBorrow这两个参数为true,表示会在每次请求之前和之后进行连接池测试,如果连接失效,就会将这条连接对象销毁,创建一个新的连接对象,但是本次数据库操作也就失败了。对于读操作可能没什么问题,再请求一次就行了,但对于充值、定时任务等重要写操作来说还不够完美。(PS:使用这两个参数,一定要配置validationQuery参数,这样才会生效。)
2、为了解决以上问题,保证每次操作都有正常的连接池使用,我们来了解一下testWhileIdle参数。这个参数为true时候,表示空闲时是进行验证,检查对象是否有效。然后minEvictableIdleTimeMillis配合timeBetweenEvictionRunsMillis,每过timeBetweenEvictionRunsMillis秒对连接池进行一次检测,将对象闲置时间超过minEvictableIdleTimeMillis秒的对象进行销毁,创建新的对象来取代。这样就能保证时刻都有正常的连接池对象存在。

C3P0的配置标准:

   
  oracle.jdbc.driver.OracleDriver   
  jdbc:oracle:thin:@localhost:1521:Test   
  Kay   
  root   
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

参考

关于MySQL的wait_timeout连接超时问题报错解决方案

文章来源于互联网:解决MySQL8小时自动断开连接的问题(DBCP配置)

发表评论