c3p0连接数据库超时问题:The last packet successfully received;The last packet sent successfully to the server

19 篇文章 1 订阅

问题描述

java.sql.SQLException: The last packet successfully received from the server was 36,483,780 milliseconds ago.  The last packet sent successfully to the server was 36,483,781 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. Query: select id,author,sectionName,releaseDate,status,title from article where  title like '%%' and releaseDate between ? AND ? order by releaseDate desc limit ?,? Parameters: [0, 2020-04-19 10:20:13, 0, 10]
	at org.apache.commons.dbutils.AbstractQueryRunner.rethrow(AbstractQueryRunner.java:320)
	at org.apache.commons.dbutils.QueryRunner.query(QueryRunner.java:349)
	at org.apache.commons.dbutils.QueryRunner.query(QueryRunner.java:287)
	at com.wei.dao.impl.ArticleDAOImpl.findByPage(ArticleDAOImpl.java:93)
	at com.wei.service.impl.ArticleServiceImpl.searchAllByCondition(ArticleServiceImpl.java:76)
	at com.wei.web.servlet.ArticleServlet.searchAllByCondition(ArticleServlet.java:150)
	at com.wei.web.servlet.ArticleServlet.doGet(ArticleServlet.java:54)
	at com.wei.web.servlet.ArticleServlet.doPost(ArticleServlet.java:180)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at com.wei.web.filter.EncodingFilter.doFilter(EncodingFilter.java:29)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Unknown Source)

在这里插入图片描述

翻译一下错误信息

The last packet successfully received from the server was 36,483,780 milliseconds ago. The last packet sent successfully to the server was 36,483,781 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. Query: select id,author,sectionName,releaseDate,status,title from article where title like '%%' and releaseDate between ? AND ? order by releaseDate desc limit ?,? Parameters: [0, 2020-04-19 10:20:13, 0, 10]

从服务器成功接收到的最后一个数据包是36483780毫秒前。最后一个成功发送到服务器的数据包是36483781毫秒前。比服务器配置的“等待超时”值长。在应用程序中使用之前,应考虑过期和/或测试连接有效性,增加客户端超时的服务器配置值,或使用Connector/J连接属性“autoReconnect=true”来避免此问题。

很容易看出是由于wait_timeout(服务器关闭非交互连接之前等待活动的秒数)造成的。mysql会根据wait_timeout设置每个空闲连接的超时时间,时间到了就会断开。

说明

c3p0连接数据库超时

在用c3p0连接mysql数据库时,时间长了会自动断开,那是因为mysql服务器默认的“wait_timeout”是8小时【也就是默认的值默认是28800秒】,也就是说一个connection空闲超过8个小时,Mysql将自动断开该connection,通俗的讲就是一个连接在8小时内没有活动,就会自动断开该连接。wait timeout的值可以设定,但最多只能是2147483,不能再大了。也就是约24.85天。但是更改wait timeout值治标不治本,所有我们要更改连接池的配置文件。

解决办法

在c3p0连接池的配置文件中加入以下配置代码(根据需要增删):

		<!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3--> 
		<property name="initialPoolSize" value="2"/>
		<!-- 连接池中保留的最小连接数,默认为:3--> 
		<property name="minPoolSize" value="2"/>
		<!--连接池中保留的最大连接数。默认值: 15 -->   
		<property name="maxPoolSize" value="15"/>
		<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 -->   
		<property name="acquireIncrement" value="2"/>
		<!--定义在从数据库获取新连接失败后重复尝试的次数。默认值: 30 ;小于等于0表示无限次-->   
        <property name="acquireRetryAttempts" value="0"/>  
        <!--重新尝试的时间间隔,默认为:1000毫秒-->   
        <property name="acquireRetryDelay" value="1000" />  
	    <!--最大空闲时间,3600秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->   
		<property name="maxIdleTime" value="3600"/>
	    <!--c3p0全局的PreparedStatements缓存的大小。如果maxStatements与maxStatementsPerConnection均为0,则缓存不生效,只要有一个不为0,则语句的缓存就能生效。如果默认值: 0-->   
		<property name="maxStatements" value="0"/>
		<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。默认值: 0 -->   
		<property name="maxStatementsPerConnection" value="0"/>
		<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。测试的表必须在初始数据源的时候就存在。Default: null-->
		<property name="preferredTestQuery" value="select 1"/>
	    <!--每1800秒检查所有连接池中的空闲连接。Default: 0 -->
		<property name="idleConnectionTestPeriod" value="1800"/>
		<!-- 获取连接时测试有效性,每次都验证连接是否可用 -->
		<property name="testConnectionOnCheckout" value="false"/>

这部分参考:https://blog.csdn.net/hui1322157301/article/details/83780353

查看mysql的wait_timeout

show global variables like 'wait_timeout';

在这里插入图片描述

默认设置28800秒,即8小时,明显连接时间55,518,630 milliseconds超过了mysql数据库设置的wait_timeout

修改命令:mysql>set global wait_timeout=28800;

C3P0作为连接池,它的最大的任务就是来管理链接的,可是实际上它并不知道这个链接是否还有效,所以,当MySQL某个链接的建立时间已经超过了wait_timeout的时候,那么这个链接实际上已经不能用了。而C3P0却还不知道,相当于C3P0持有了不能使用的链接。

3.问题解决

解决的方法有3种:

  • 增加wait_timeout的时间。
  • 减少Connection pools中connection的lifetime。
  • 测试Connection pools中connection的有效性。
  • JDBC URL上面加一个autoReconnect=true ,在新的connector/J版本里面已经deprecated了,文档里面建议不要使用.

我用的这个

在c3p0连接池的配置文件中加入以下配置代码(根据需要增删):

		<!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3--> 
		<property name="initialPoolSize" value="2"/>
		<!-- 连接池中保留的最小连接数,默认为:3--> 
		<property name="minPoolSize" value="2"/>
		<!--连接池中保留的最大连接数。默认值: 15 -->   
		<property name="maxPoolSize" value="15"/>
		<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 -->   
		<property name="acquireIncrement" value="2"/>
		<!--定义在从数据库获取新连接失败后重复尝试的次数。默认值: 30 ;小于等于0表示无限次-->   
        <property name="acquireRetryAttempts" value="0"/>  
        <!--重新尝试的时间间隔,默认为:1000毫秒-->   
        <property name="acquireRetryDelay" value="1000" />  
	    <!--最大空闲时间,3600秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->   
		<property name="maxIdleTime" value="3600"/>
	    <!--c3p0全局的PreparedStatements缓存的大小。如果maxStatements与maxStatementsPerConnection均为0,则缓存不生效,只要有一个不为0,则语句的缓存就能生效。如果默认值: 0-->   
		<property name="maxStatements" value="0"/>
		<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。默认值: 0 -->   
		<property name="maxStatementsPerConnection" value="0"/>
		<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。测试的表必须在初始数据源的时候就存在。Default: null-->
		<property name="preferredTestQuery" value="select 1"/>
	    <!--每1800秒检查所有连接池中的空闲连接。Default: 0 -->
		<property name="idleConnectionTestPeriod" value="1800"/>
		<!-- 获取连接时测试有效性,每次都验证连接是否可用 -->
		<property name="testConnectionOnCheckout" value="false"/>

这部分参考:https://blog.csdn.net/hui1322157301/article/details/83780353

注意下面的写法与上面参考中的不一样,里面的值的写法,按照他那样写值,我这不起效果

这里最重要的一项是idleConnectionTestPeriod:隔多少秒检查所有连接池中的空闲连接,默认为0表示不检查;看看你的配置是否少了这个配置,这里的秒数一定要小于mysql的全局的超时秒数

show global variables like '%timeout%'; 

最终的c3p0-config.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<default-config>
		<property name="user">root</property>
		<property name="password">1234</property>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///kjxn</property>
		
		<!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3--> 
		<property name="initialPoolSize">2</property>
		<!-- 连接池中保留的最小连接数,默认为:3--> 
		<property name="minPoolSize">2</property>
		<!--连接池中保留的最大连接数。默认值: 15 -->   
		<property name="maxPoolSize"></property>
		<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 -->   
		<property name="acquireIncrement">2</property>
		<!--定义在从数据库获取新连接失败后重复尝试的次数。默认值: 30 ;小于等于0表示无限次-->   
        <property name="acquireRetryAttempts">0</property>  
        <!--重新尝试的时间间隔,默认为:1000毫秒-->   
        <property name="acquireRetryDelay">1000</property>  
	    <!--最大空闲时间,3600秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->   
		<property name="maxIdleTime">3600</property>
	    <!--c3p0全局的PreparedStatements缓存的大小。如果maxStatements与maxStatementsPerConnection均为0,则缓存不生效,只要有一个不为0,则语句的缓存就能生效。如果默认值: 0-->   
		<property name="maxStatements">0</property>
		<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。默认值: 0 -->   
		<property name="maxStatementsPerConnection">0</property>
		<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。测试的表必须在初始数据源的时候就存在。Default: null-->
		<property name="preferredTestQuery">select 1</property>
	    <!--每1800秒检查所有连接池中的 空闲连接。Default: 0 -->
		<property name="idleConnectionTestPeriod">1800</property>
		<!-- 获取连接时测试有效性,每次都验证连接是否可用 -->
		<property name="testConnectionOnCheckout">false</property>
	</default-config> <!-- This app is massive! -->
</c3p0-config> 

log中也给了解决方案:

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.

简单点概括,在配置C3P0的时候,如果要防止链接失效的情况,可以配置一个testConnectionOnCheckout的属性,当时该属性会比较大的影响性能。

如果比较在意性能的,可以设置testConnectionOnCheckout为false,设置testConnectionOnCheckin为true,设置idleConnectionTestPeriod为30秒

spring中配置数据源

这里参考:https://www.cnblogs.com/xiaosheblog/p/7637612.html
在这里插入图片描述
properties文件

在这里插入图片描述
启动项目,通过输出日志可看到,每30秒连接池会自动测试连接了。
在这里插入图片描述

后两种方法显然不太实用

增加mysql数据库的超时时间,由于最大超时时间是2147483一年,不可无限制增加,再说也不应该随便增加。'autoReconnect=true'如果使用的时候reconnect会影响效率,而且据说mysql5以上无效(本人没试),而且官方也不建议
http://bugs.mysql.com/bug.php?id=5020

采用c3p0提供的方案

可参考:http://www.mchange.com/projects/c3p0/index.html#configuring_connection_testing

The most reliable time to test Connections is on check-out. But this is also the most costly choice from a client-performance perspective. Most applications should work quite reliably using a combination of idleConnectionTestPeriod and testConnectionOnCheckin. Both the idle test and the check-in test are performed asynchronously, which can lead to better performance, both perceived and actual. 
 
For some applications, high performance is more important than the risk of an occasional database exception. In its default configuration, c3p0 does no Connection testing at all. Setting a fairly long idleConnectionTestPeriod, and not testing on checkout and check-in at all is an excellent, high-performance approach. 

最可靠的是退出时间测试连接。但这也是最昂贵的从客户端性能的角度选择。大多数应用程序应该使用idleConnectionTestPeriod和testConnectionOnCheckin相当可靠。闲置的测试和登记测试是异步执行的,这可能导致更好的性能,感知和实际。

对于某些应用程序,高性能比偶尔的风险更重要数据库异常。在默认配置中,c3p0没有连接测试。设置一个相当长的idleConnectionTestPeriod,而不是测试是一个很好的检验和登记,高性能的方法。

考虑再三可以如下设置

设置c3p0中连接池内连接的生存周期(idleConnectionTestPeriod)小于数据库中的wait_timeout的值

<!--每5小时检查所有连接池中的空闲连接。防止mysql wait_timeout(默认的为8小时) -->
		<property name="idleConnectionTestPeriod" value="18000"/>

这个解决方案参考:https://blog.csdn.net/honghailiang888/article/details/52691591

修改msyql 配置 ,不推荐

保证应用在MySQL的’wait_timeout’时间内,至少访问一次数据库,配置文件增加心跳检测部分

sys.db.initialSize=10
sys.db.maxIdle=50
sys.db.minIdle=5
sys.db.maxActive=50
sys.db.logAbandoned=true
sys.db.removeAbandoned=true
sys.db.removeAbandonedTimeout=120
sys.db.maxWait=60000
sys.db.type=mysql
dialect=MYSQL
sys.db.class=com.mysql.jdbc.Driver

sys.db.url=jdbc:mysql://localhost:3306/test?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=UTF-8
sys.db.username=root
sys.db.password=123456
<!-- 数据源定义 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${sys.db.class}"/>
		<property name="url" value="${sys.db.url}"/>
		<property name="username" value="${sys.db.username}"/>
		<property name="password" value="${sys.db.password}"/> 
		<property name="initialSize" value="${sys.db.initialSize}"/><!-- 初始化连接 -->
		<property name="maxIdle" value="${sys.db.maxIdle}"/><!-- 最大空闲连接 -->
		<property name="minIdle" value="${sys.db.minIdle}"/><!-- 最小空闲连接 -->
		<property name="maxActive" value="${sys.db.maxActive}"/><!-- 最大连接数量 -->
		<property name="logAbandoned" value="${sys.db.logAbandoned}"/><!-- 是否在自动回收超时连接的时候打印连接的超时错误 -->
		<property name="removeAbandoned" value="${sys.db.removeAbandoned}"/><!-- 是否自动回收超时连接 -->
		<property name="removeAbandonedTimeout" value="${sys.db.removeAbandonedTimeout}"/><!-- 超时时间(以秒数为单位) -->
		<property name="maxWait" value="${sys.db.maxWait}"/><!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
		
		
		<!-- sql 心跳检测 -->
		<property name= "testWhileIdle" ><value>true</value></property><!-- 起了一个 异步Evict的TimerTask定时线程进行控制 定时对线程池中的链接进行validateObject校验,对无效的链接进行关闭后,会调用ensureMinIdle,适当建立链接保证最小的minIdle连接数 -->
		<property name= "testOnBorrow" ><value>false</value></property><!-- 在进行borrowObject进行处理时,对拿到的connection进行validateObject校验 -->
		<property name= "testOnReturn" ><value>false</value></property><!-- 进行returnObject对返回的connection进行validateObject校验 -->
		<property name= "validationQuery" ><value>select 1</value></property><!-- 代表检查的sql -->
		<property name= "validationQueryTimeout" ><value>1</value></property><!-- 代表在执行检查时,通过statement设置,statement.setQueryTimeout(validationQueryTimeout) -->
		<property name= "timeBetweenEvictionRunsMillis" ><value>28700</value></property><!-- 设置的Evict线程的时间,多久检查一次,建议小于mysql默认时间默认的8小时(即 28800秒),单位ms,大于0才会开启evict检查线程 -->
		<property name= "numTestsPerEvictionRun" ><value>${sys.db.maxActive}</value></property><!-- 代表每次检查链接的数量,建议设置和maxActive一样大,这样每次可以有效检查所有的链接. -->
		<property name= "minEvictableIdleTimeMillis"><value>18000000</value></property><!--  -->
		
	</bean>

这部分参考:https://blog.csdn.net/u014755645/article/details/85160430

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值