使用Connector/J连接MySQL数据库,程序运行较长时间后就会报以下错误:
Communications link failure,The last packet successfully received from the server was *** millisecond ago.The last packet successfully sent to the server was *** millisecond ago。
其中错误还会提示你修改wait_timeout或是使用Connector/J的autoReconnect属性避免该错误。
后来查了一些资料,才发现遇到这个问题的人还真不少,大部分都是使用连接池方式时才会出现这个问题,短连接应该很难出现这个问题。这个问题的原因:
MySQL服务器默认的“wait_timeout”是28800秒即8小时,意味着如果一个连接的空闲时间超过8个小时,MySQL将自动断开该连接,而连接池却认为该连接还是有效的(因为并未校验连接的有效性),当应用申请使用该连接时,就会导致上面的报错。
修改MySQL的参数,wait_timeout最大为31536000即1年,在my.cnf中加入:
[mysqld]
wait_timeout=31536000
interactive_timeout=31536000
重启生效,需要同时修改这两个参数。
解决方法:
<property name="validationQuery" value="select 1" />
<property name="testOnBorrow" value="true" />
<property name="testWhileIdle" value="true"/>
原因:
应用druid连接池,长时间没有请求造成的数据库连接超时,抛出异常:
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
比如开启事务,然后其他业务操作,然后db操作。
关于数据库连接池的最大空闲时间的配置
java的所有的连接池 无论是c3p0、dbcp还是druid,都有一个类似maxWait或者maxIdleTime配置项。具体含义就是当连接长时间没有向服务器发请求的 时候,断开这个连接,避免对数据库连接的浪费。这个时间不是随便设的,它的依据是数据库的连接最大空闲时间。
以mysql为例,它有个_wait_timeout 参数,你可以通过命令show variables like “%timeout%”查看
+—————————–+———-+
| Variable_name | Value |
+—————————–+———-+
| connect_timeout | 10 |
| delayed_insert_timeout | 300 |
| innodb_flush_log_at_timeout | 1 |
| innodb_lock_wait_timeout | 50 |
| innodb_rollback_on_timeout | OFF |
| interactive_timeout | 28800 |
| lock_wait_timeout | 31536000 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| rpl_stop_slave_timeout | 31536000 |
| slave_net_timeout | 3600 |
| wait_timeout | 28800 |
+—————————–+———-+
wait_timeout默认的时候是8个小时28800秒,但是有时候可能被不经意修改。这个时间表示当连接在28800个时间没有向服务器发请求的时候,它就会断开这个连接。
你可以通过set global wait_timeout=60000来修改。不过好像interactive_timeout也必须同时修改才可以,要不wait_timeout改不 了,它会用interactive_timeout的值初始化wait_timeout(这个原理又是另外一回事了).
所以在使用连接池的时候maxWait或者maxIdleTime,这个参数必须设置为小于wait_timeout的值,否则的话,当你的连接长 时间没和数据库交互,服务器早把你的连接断开了,而你的连接池还认为是有效的连接,除非你设置testOnBorrow或者testOnReturn设置 为true,这样当连接每次从连接池中取出或者放回的时候检查下连接是否有效。不过这样回牺牲一点性能。
否则你就会收到下面这样类似的异常,特别是经过一个耗时长的查询之后,这个连接再用于进行下次数据库操作的时候。
The last packet successfully received from the server was 1,867,460 milliseconds ago. The last packet sent successfully to the server was 0 milliseconds ago.; nested exception is com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
http://zhaoyanblog.com/archives/486.html
https://github.com/alibaba/druid/issues/1022