问题:
com.alibaba.druid.pool.DruidDataSource - discard connection
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 109,470 milliseconds ago. The last packet sent successfully to the server was 0 milliseconds ago.java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
原因分析:
数据库连接强行断开,但是web应用不知道数据库已经断开(或者理解为连接池子不知道数据库已经断开),还是通过连接池子连接数据库与数据库的交互,这样会导致如上错误。
解决方案:
1.查询mysql数据库的非交互式最大等待时间wait_timeout
一般数据库默认的wait_timeout为8小时。查询wait_timeout的命令如下:
mysql> show global variables like 'wait_timeout';
如果数据库连接空闲时间大于wait_timeout,则操作web应用就会出现上述异常,解决办法可以设置wait_timeout的时间为一个适合实际应用场景的时间。设置命令为:
set global wait_timeout=28800;
时间单位为ms,但是wait_timeout设置页不要太大,如果太大会导致数据库连接打开时间过长,在show processlist时,看到很多sleep状态的连接,从而造成too many connections错误;如果wait_timeout设置太小的话会导致连接关闭很快,从而使一些预设置的连接不起作用。
2.在确认1步骤wait_timeout配置没有问题的话,查看数据库配置设置是否有问题
dbcp的参数设置意义
参考连接:http://commons.apache.org/proper/commons-dbcp/configuration.html
字段名称 | 设置值 | 说明 |
initialSize | 5 | 初始化连接:连接池启动时创建的初始化连接数据量 |
maxActive | 20 | 最大活动连接:连接池在同一时间能够分配的最大活动连接的数量,如果设置为非正数则表示不限制 |
maxIdle | 10 | 最大空闲连接:连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放,如果设置为负数表示不限制 |
minIdle | 2 | 最小空闲连接数:当数据库连接池的空闲数少于这个数目的时候,数据库自动创建空闲连接,当设置为0的时候,不创建空闲连接 |
maxWait | 1800 | 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间(以毫秒计数),超过时间则抛出异常,如果设置为-1则无限等待 |
minEvictableIdleTimeMillis | 300000 | 连接池中的空闲连接保持空闲不被空闲连接回收器线程回收的最小时间值,单位毫秒 |
timeBetweenEvictionRunsMillis | 120000 | 空闲连接回收器线程休眠的时间值,即每隔这个时间值空闲连接回收器线程回收空闲连接,单位毫秒 |
numTestsPerEvictionRun | 3 | 每次空闲连接回收器线程线程运行的时候检查的连接数量 |
validationQuery | select 1 | 在把连接返回给调用者之间,SQL查询,用来验证从连接池子取出连接,是一个用来检测连接是否有效的SQL,要求是一个查询语句,如果 validationQuery为null,testWhileIdle、testOnBorrow、testOnReturn都不起作用 |
testWhileIdle | true | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
testOnBorrow | false | 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个.申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
username | / | 数据库连接的用户名 |
password | / | 数据库连接的密码 |
url | / | 数据库连接的url |
driverClassName | / | 数据库连接的驱动类的类名,例如 com.mysql.jdbc.Driver |
2.1通过设置
<property name="validationQuery" value="select 1" />
数据库每次执行sql会额外执行一条提供的validationQuery sql,来减少出现文章中提到的错误问题。
2.2通过配置timeBetweenEvictionRunsMillis和minEvictableIdleTimeMillis
如果timeBetweenEvictionRunsMillis大于0,每过 timeBetweenEvictionRunsMillis毫秒Evictor会调用evict()方法,检查连接池中的连接的闲置时间是否大于 minEvictableIdleTimeMillis毫秒,是则销毁此对象,然后调用ensureMinIdle方法检查确保池中对象个数不小于_minIdle。如果连接池的连接数小于最小空闲连接数,则创建数据库连接,同时检查连接池的连接是否小于maxIdle,是则把刚创建的连接放入连接池中,否则销毁此对象。
数据库在重启后minEvictableIdleTimeMillis前访问web应用,数据库连接池子连接的是老的连接,所以会出现文章中提到的问题。这时可以设置minEvictableIdleTimeMillis的大小要小于mysql的wait_timeout时间,并且minEvictableIdleTimeMillis的值不要设置太小,太小的话会增加系统开销。timeBetweenEvictionRunsMillis和minEvictableIdleTimeMillis时间可以适当调整,具体以实际情况为准。
2.3JDBC配置mysql连接url的重连机制
在数据库的连接url中增加数据库自动重连接机制autoReconnect=true