最近测试环境老抛出这个错,
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 53,014,427 milliseconds ago. The last packet sent successfully to the server was 53,014,427 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.
at sun.reflect.GeneratedConstructorAccessor58.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:990)
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3706)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2506)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2675)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2465)
at com.mysql.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl.java:4776)
at org.apache.commons.dbcp.DelegatingConnection.setAutoCommit(DelegatingConnection.java:331)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.setAutoCommit(PoolingDataSource.java:317)
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:267)
... 58 common frames omitted
引起原因:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:从服务器成功接收到的最后一个数据包是53,014,427毫秒之前。 成功发送到服务器的最后一个数据包是53,014,427毫秒之前。 大于服务器配置的“ wait_timeout”值。 您应考虑在应用程序中使用连接之前使连接有效性到期和/或对其进行测试,或者增加服务器为客户端超时配置的值,或者使用Connector / J连接属性'autoReconnect = true'来避免此问题。
Caused by: java.net.SocketException: 断开的管道 (Write failed)
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3688)
... 65 common frames omitted
分析可知,数据库服务端也是一个线程池,服务端的线程长时间不用、关闭了,可客户端并不知情,针对这种情况,可想而知、需要一个检测机制。
数据库是长连接的,我们认识一下长连接:
而长连接通常就是:
连接-》数据传输-》保持连接-》数据传输-》保持连接-》…………-》关闭连接;
这就要求长连接在没有数据通信时,定时发送数据包,以维持连接状态,短连接在没有数据传输时直接关闭就行了
什么时候用长连接,短连接?
长连接主要用于在少数客户端与服务端的频繁通信,因为这时候如果用短连接频繁通信常会发生Socket出错,并且频繁创建Socket连接也是对资源的浪费。
但是对于服务端来说,长连接也会耗费一定的资源,需要专门的线程(unix下可以用进程管理)来负责维护连接状态。
总之,长连接和短连接的选择要视情况而定。
首先,如果使用了长连接而长期没有对数据库进行任何操作,那么在timeout值后,mysql server就会关闭此连接,而客户端在执行查询的时候就会得到一个类似于“MySQL server has gone away“这样的错误。
在使用mysql_real_connect连接数据库之后,再使用mysql_options( &mysql, MYSQL_OPT_RECONNECT, … ) 来设置为自动重连。这样当mysql连接丢失的时候,使用mysql_ping能够自动重连数据库。如果是在mysql 5.1.6之前,那么则应在每次执行完real_connect 之后执行mysql_options( &mysql, MYSQL_OPT_RECONNECT, … ) ,如果是mysql 5.1.6+,则在connect之前执行一次就够了。
通过对长连接的了解,服务端针对不用的连接可以设置–timeout,废弃连接、客户端需要知道这个操作。
追踪数据库连接池配置,发现只有线程池基础配置,没有检测功能
<bean id="mysqlDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${db.mysql.driverClassName}"/>
<property name="url" value="${db.mysql.url}&characterEncoding=UTF-8&allowMultiQueries=true"/>
<property name="username" value="${db.mysql.username}" />
<property name="password" value="${db.mysql.password}" />
// 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
// 验证使用的SQL语句
<property name="validationQuery" value="select 1" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="10"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="100"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="50"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="10"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000"></property>
</bean>
参考 https://www.cnblogs.com/chrischennx/p/7279215.html?utm_source=itdadao&utm_medium=referral
添加检测功能
修改后配置为,
<bean id="mysqlDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${db.mysql.driverClassName}"/>
<property name="url" value="${db.mysql.url}&characterEncoding=UTF-8&allowMultiQueries=true"/>
<property name="username" value="${db.mysql.username}" />
<property name="password" value="${db.mysql.password}" />
// 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
<property name="testWhileIdle" value="true" />
// 借出连接时不要测试,否则很影响性能
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
// 验证使用的SQL语句
<property name="validationQuery" value="select 1" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="10"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="100"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="50"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="10"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000"></property>
// 每30秒运行一次空闲连接回收器
<property name="timeBetweenEvictionRunsMillis" value="60000" />
// 在每次空闲连接回收器线程(如果有)运行时检查的连接数量
<property name="numTestsPerEvictionRun" value="10" />
// 池中的连接空闲30分钟后被回收
<property name="minEvictableIdleTimeMillis" value="120000" />
</bean>
问题解决。。