Spring Boot集成Druid异常discard long time none received connection.
Spring Boot集成Druid异常
在Spring Boot集成Druid项目中,发现错误日志中频繁的出现如下错误信息:
discard long time none received connection. , jdbcUrl : jdbc:mysql://******?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8, version : 1.2.3, lastPacketReceivedIdleMillis : 172675
经过排查发现是Druid版本导致的异常,在1.2.2及以前版本并未出现如此异常。而在其以上版本均存在此问题,下面就来分析一下异常原因及解决方案。
异常分析
首先上面的异常并不影响程序的正常运行,但作为程序员看到程序中不停的出现异常还是难以忍受的。所以还是要刨根问底的解决一下的。
跟踪堆栈信息会发现对应的异常是从com.alibaba.druid.pool.DruidAbstractDataSource#testConnectionInternal方法中抛出的,对应的代码如下:
if (valid && isMySql) { // unexcepted branchlong lastPacketReceivedTimeMs = MySqlUtils.getLastPacketReceivedTimeMs(conn);if (lastPacketReceivedTimeMs > 0) {long mysqlIdleMillis = currentTimeMillis - lastPacketReceivedTimeMs;if (lastPacketReceivedTimeMs > 0 //&& mysqlIdleMillis >= timeBetweenEvictionRunsMillis) {discardConnection(holder);String errorMsg = "discard long time none received connection. "+ ", jdbcUrl : " + jdbcUrl+ ", jdbcUrl : " + jdbcUrl+ ", lastPacketReceivedIdleMillis : " + mysqlIdleMillis;LOG.error(errorMsg);return false;}}
}
上述代码中,MySqlUtils.getLastPacketReceivedTimeMs(conn) 是获取上一次使用的时间,mysqlIdleMillis 就是计算出来空闲的时间,timeBetweenEvictionRunsMillis 是常量60秒。如果连接空闲了60秒以上,那就discardConnection(holder) 丢弃这个旧连接并顺带打印了一个日志LOG.warn(errorMsg)。
原理追踪
在上述代码中,我们看到进入该业务逻辑是有前提条件的,也就是valid和isMySql变量同时为true。isMySql为true是必须的,我们使用的本身就是Mysql数据库。那么是否可以让valid为false呢?这样不就不会进入该业务处理了吗?
来看看valid的来源,还是在该方法的上面:
boolean valid = validConnectionChecker.isValidConnection(conn, validationQuery, validationQueryTimeout);
我们找到validConnectionChecker的Mysql实现子类MySqlValidConnectionChecker,该类中对isValidConnection的实现如下:
public boolean isValidConnection(Connection conn, String validateQuery, int validationQueryTimeout) throws Exception {if (conn.isClosed()) {return false;}if (usePingMethod) {if (conn instanceof DruidPooledConnection) {conn = ((DruidPooledConnection) conn).getConnection();}if (conn instanceof ConnectionProxy) {conn = ((ConnectionProxy) conn).getRawObject();}if (clazz.isAssignableFrom(conn.getClass())) {if (validationQueryTimeout <= 0) {validationQueryTimeout = DEFAULT_VALIDATION_QUERY_TIMEOUT;}try {ping.invoke(conn, true, validationQueryTimeout * 1000);} catch (InvocationTargetException e) {Throwable cause = e.getCause();if (cause instanceof SQLException) {throw (SQLException) cause;}throw e;}return true;}}String query = validateQuery;if (validateQuery == null || validateQuery.isEmpty()) {query = DEFAULT_VALIDATION_QUERY;}Statement stmt = null;ResultSet rs = null;try {stmt = conn.createStatement();if (validationQueryTimeout > 0) {stmt.setQueryTimeout(validationQueryTimeout);}rs = stmt.executeQuery(query);return true;} finally {JdbcUtils.close(rs);JdbcUtils.close(stmt);}}
我们可以看到上述方法中有三个返回的地方:第一个连接已关闭;第二个使用ping的形式进行检查;第三,使用select 1的方式进行检查。而使用ping的形式检查时,无论是否抛异常都会返回true。这里我们禁用该模式即可。
进入ping的业务逻辑主要靠变量usePingMethod来判断,追踪代码会发现在这里进行的设置:
public void configFromProperties(Properties properties) {String property = properties.getProperty("druid.mysql.usePingMethod");if ("true".equals(property)) {setUsePingMethod(true);} else if ("false".equals(property)) {setUsePingMethod(false);}
}
那么,也就是说,当我们把系统属性druid.mysql.usePingMethod设置为false即可禁用该功能。
禁用Ping Method
找到了问题的根源,那么剩下的就是如何禁用了,通常有三种形式。
第一,在启动程序时在运行参数中增加:-Ddruid.mysql.usePingMethod=false。
第二,在Spring Boot项目中,可在启动类中添加如下静态代码快:
static {System.setProperty("druid.mysql.usePingMethod","false");
}
第三,类文件配置。在项目的DruidConfig类中新增加:
/*
* 解决druid 日志报错:discard long time none received connection:xxx
* */
@PostConstruct
public void setProperties(){System.setProperty("druid.mysql.usePingMethod","false");
}
至此,已可以成功关闭该功能,异常信息再也不会出现了。
为什么要清空空闲60秒以上的连接
猜测,阿里给数据库设置的数据库空闲等待时间是60秒,mysql数据库到了空闲等待时间将关闭空闲的连接,以提升数据库服务器的处理能力。
MySQL的默认空闲等待时间是8小时,就是「wait_timeout」的配置值。如果数据库主动关闭了空闲的连接,而连接池并不知道,还在使用这个连接,就会产生异常。
面试系列
- 《面试题:聊聊TCP的粘包、拆包以及解决方案》
- 《面试题:重写equals方法为什么通常会重写hashcode方法?》
- 《面试官:如何找出字符串中无重复最长子串?》
- 《还不懂Java的泛型?只用这一篇文章,保证你面试对答如流》
- 《面试题:将字符串反转的8种方法,你能想到几种?》
程序新视界
公众号“程序新视界”,一个让你软实力、硬技术同步提升的平台,提供海量资料
Spring Boot集成Druid异常discard long time none received connection.相关推荐
- Spring Boot 集成 Druid 监控数据源
关注"Java后端技术全栈" 回复"面试"获取全套大厂面试资料 Druid 介绍 Druid 是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池.插件框架和 ...
- spring boot 集成druid数据库连接池,并打印sql
spring boot 2.x 集成druid pom文件配置 <dependencies><dependency><groupId>org.springframe ...
- Spring Boot集成Druid监控
package com.xxxxxxx.framework.datasource.druid;import com.alibaba.druid.support.http.WebStatFilter;i ...
- Spring Boot 集成MyBatis
Spring Boot 集成MyBatis Spring Boot 系列 Spring Boot 入门 Spring Boot 属性配置和使用 Spring Boot 集成MyBatis Spring ...
- 有手就行的 Spring Boot 集成 Shiro
前言 Apache Shiro 是 Java 的一个安全框架.目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Se ...
- Spring Boot 使用 Druid 连接池详解
Spring Boot 使用 Druid 连接池详解 Alibaba Druid 是一个 JDBC 组件库,包含数据库连接池.SQL Parser 等组件,被大量业务和技术产品使用或集成,经历过严苛的 ...
- Spring Boot使用Druid和监控配置
完美与Spring Boot集成. 1.编写Spring Boot Druid配置类 DruidDataSourceProperties.java package org.paascloud.ops. ...
- Spring Boot下Druid连接池的使用配置分析
引言: 在Spring Boot下默认提供了若干种可用的连接池,Druid来自于阿里系的一个开源连接池,在连接池之外,还提供了非常优秀的监控功能,这里讲解如何与Spring Boot实现集成. 1. ...
- Spring Boot 集成 Mybatis 实现双数据源
转载自 Spring Boot 集成 Mybatis 实现双数据源 这里用到了Spring Boot + Mybatis + DynamicDataSource配置动态双数据源,可以动态切换数据源 ...
最新文章
- 揭秘互联网人群层级,你属于第几级?
- Android新权限机制 AppOps
- SpringBoot+Jquery实现前后端数据交互
- 【NLP】EMNLP'21 | 让压缩语言模型自动搜索最优结构!
- 全国计算机等级考试题库二级C操作题100套(第02套)
- win7内存占用过高怎么处理
- Kylin修改默认hbase namespace命名空间default的解决方案
- Sliverlight中使用Path绘制复杂几何图形
- mysql5.7不区分大小写_转载:mysql5.7设置不区分大小写
- 数据科学包2-pandas快速入门1
- 还不会回答Spring Boot和Spring MVC的关系?大厂Java高级面试官告诉你答案!
- 答粉丝问|火狐浏览器插件简介
- Android手机游戏开发入门教程
- 主数据管理(MDM)与元数据管理
- python函数返回值可以有多个吗_Python函数中如何返回多个值?(代码示例)
- 四川大学计算机专业调剂,四川大学计算机学院(软件学院)研究生调剂
- 51单片机定时器中断按键消抖(无延时)
- 优化| 手把手教你学会杉树求解器(COPT)的安装、配置与测试
- 分析报告_问题界定篇
- outlook的archive pst丢失后
热门文章
- 移动端touch事件和click事件的区别
- 网络系统设计过程中,物理网络设计阶段的任务是(70)。【答案】A
- [CSCCTF 2019 Qual] FlaskLight
- 办公室必备-上班偷看小说利器
- 终于有一篇能让小白更容易理解GC算法的文章了
- 蓝桥杯刷题日记 更新到2022/2/5
- 成长型企业的好帮手:超融合小身材却有大能量
- 《非Pad勿扰》风靡平板电脑界
- python怎么编写对称图案_python – 无论matplotlib中的箭头角度如何,都使箭头形状对称...
- 谈谈运营经验:颠覆式创新