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种方法,你能想到几种?》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/554790.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

局部变量为什么必须赋值才可以使用

在java内存模型中规定&#xff0c;一个新的变量只能在主存中初始化&#xff0c;不允许在工作内存中直接使用一个未被初始化的变量。 工作内存可以理解为局部变量定义的内存区域&#xff0c;也就是线程的工作内存。所谓局部变量就是线程私有的不共享的空间。 类加载准备阶段 类变…

Java 赋值 “=” 讲解

前言 我们从接触java第一天&#xff0c;就是到 是赋值的意思&#xff0c;把等号右边结果的值&#xff0c;赋给等号左边的变量&#xff0c;那具体是怎样赋值呢&#xff1f;你有了解过吗&#xff1f; 1.0版本 大家都知道&#xff0c;java中有 8大基本类型&#xff0c;对于基本…

Linux 系统管理命令:时间、进程、网络、磁盘、关机重启等 top命令用法详解

文章目录系统管理常用命令1. 日期1.1 查看日历: cal1.2 查看/设置时间: date2. 进程2.1 查看进程信息: ps2.2 动态显示进程信息: top2.3 终止进程: kill2.4 服务的管理: service3. 网络3.1 网卡信息查询与配置: ifconfig3.2 检测远程主机连通性: ping3.3 查看网络状态(监听端口…

BigDecimal 加减乘除顺序验证

结论&#xff1a;BigDecimal 与常识的加减乘除计算优先顺序无关联&#xff0c;采用的是方法调用顺序&#xff0c;顺序执行。 public static void main(String[] args) {BigDecimal two new BigDecimal("2");BigDecimal one new BigDecimal("1");System.…

LocalDate详解

LocalDate使用 localDate时间创建方式 /*** localDate时间创建方式* 获取当前时间*/Testpublic void localDateCreate() {LocalDate yyyyMMdd LocalDate.now();LocalTime HHmmssSSS LocalTime.now();LocalDateTime yyyyMMddHHmmssSSS LocalDateTime.now();System.out.print…

Java8中计算时间的四种方式及区别Period、Duration、ChronoUnit、Until 时间区间Duration的简单使用

一.简述 在Java8中&#xff0c;我们可以使用以下类来计算日期时间差异&#xff1a; 1.Period 2.Duration 3.ChronoUnit二.Period类 Period类计算只有年、月、日 计算的是LocalDate两个时间间隔的年月日 public static void main(String[] args) {LocalDate startTime Loc…

[JAVA基础] 成员变量和局部变量(一看就懂的总结归纳篇)

引言 成员变量和局部变量在每种编程语言中都有涉及&#xff0c;如果之前了解过其他语言的成员变量或者局部变量&#xff0c;那么在学习java中的成员变量和局部变量时可以看看有那些联系和不同&#xff0c;这一块的东西也不能说难&#xff0c;如果第一次接触可能会感觉有点乱&a…

【Java多线程】内存模型JMM—主内存与工作内存分析

文章目录JAVA内存模型JVM主内存与工作内存描述JVM内存间交互规则JVM先行发生原则内存交互基本操作的 3 个特性原子性(Atomicity)可见性(Visibility)有序性(Ordering)上述内存模型与Java多线程之间的问题JAVA内存模型 共享变量&#xff1a;如果一个变量在多个线程的工作内存中都…

Java 两个日期之间相差的天数计算 Calendar的DAY_OF_MONTH, DAY_OF_YEAR, DATE的区别

项目开发过程中经常遇到这类需求&#xff0c;计算两个日期之间的差&#xff0c;今天我系统总结一下这个技术点&#xff1a; 1、两个日期之间相差的天数&#xff0c;日期为单位&#xff08;比如相差两秒&#xff0c;可能就相差一天&#xff0c;1.12:23:59&#xff1a;59和13:01…

JMM中工作内存和主内存的关系

Java运行时的数据区域分布&#xff1a; 一、共享区域&#xff1a; &#xff08;1&#xff09;方法区:存储了每个类的信息&#xff08;包括类的名称、方法信息、字段信息&#xff09;、静态变量、常量以及编译器编译后的代码等。其中常量池就是在此区域&#xff1a;记录了每一…

使用MyBatis获得包含内嵌对象或对象集合的结果——MyBatis结果集封装(复杂对象,连接查询结果集封装)

最终要获得的SysUser对象 public class SysUser implements Serializable {//普通String属性private String userId;private String userName;private String userPhone;private String userPassword;private String userLastLoginTime;private String userCreateTime;private…

SpringBoot配置MyBatis的sql执行超时时间(mysql)

当某些sql因为不知名原因堵塞时&#xff0c;为了不影响后台服务运行&#xff0c;想要给sql增加执行时间限制&#xff0c;超时后就抛异常&#xff0c;保证后台线程不会因为sql堵塞而堵塞。 方法一 yml全局配置&#xff1a;单数据源可以&#xff0c;多数据源时会失效 方法二 j…

HTTP协议中的302,303状态码

之前也只知道302,303是请求重定向,但是当被问到302,303的具体区别是什么的时候我有点迷,现在就为了加强记忆,来了解下具体情况: 302是http1.0的内容&#xff0c;303是http1.1的内容。301和302本来在规范中是不允许重定向时改变请求方法的&#xff08;将POST改为GET&#xff09…

Java8中Stream为什么要boxed

在介绍boxed前&#xff0c;先看下面一个案例 Java8中的有个生成随机数的Random类&#xff0c;先看下面代码&#xff0c;功能是生成100个随机数。数字在0到100之间。 Random random new Random(); IntStream intStream random.ints(0, 100); intStream.lim…

Spring工具类:FileCopyUtils、StreamUtils

文章目录FileCopyUtilsStreamUtils参考资料Spring 在 org.springframework.util 包提供了很多实用的工具类。今天关心一下Copy 相关的两个&#xff1a; FileCopyUtils FileCopyUtils就是对StreamUtils的copy方法进行了封装&#xff0c;在每次复制完毕后关闭流。&#xff08;因…

Spring自带工具类(断言、ObjectUtils、FileCopyUtils、ResourceUtils、StreamUtils、ReflectionUtils、AopUtils、AopCont)

文章目录断言对象、数组、集合文件、资源、IO 流反射、AOP断言 断言是一个逻辑判断&#xff0c;用于检查不应该发生的情况Assert 关键字在 JDK1.4 中引入&#xff0c;可通过 JVM 参数-enableassertions开启SpringBoot 中提供了 Assert 断言工具类&#xff0c;通常用于数据合法…

Arrays.asList踩坑——引发的Exception in thread “main“ java.lang.UnsupportedOperationException

Exception in thread “main” java.lang.UnsupportedOperationException 如果你尝试修改Arrays.asList方法生产的List&#xff0c;那么就会报这个错误 public static void main(String[] args) {Integer[] arr new Integer[]{7,8,9};List<Integer> list Arrays.asLi…

GIS算法:JAVA拓扑套件JTS

常用可以用于GIS数据处理和空间计算的java包有geotool和jts。 相对来说&#xff0c;geotool功能更全面&#xff0c;还可以用于数据转换、瓦片地图发布、栅格影像分析等&#xff0c;jts只能进行基本的数据处理和空间计算。 但大多数情况下jts就完全够用了。 geotool的官网&am…

Java本地远程服务器debug调试详解

日常我们debug是经常用的&#xff0c;但是本地还好说&#xff0c;远程debug就有点难度&#xff0c;而且有时候必须要在预演&#xff0c;测试环境的服务器去debug&#xff0c;举个例子&#xff0c;需要https&#xff0c;公网&#xff0c;域名之类的&#xff0c;测试服务器这些有…

Linux “ll“ 命令详解

“ls -l” “ls -al” ll 用来查询当前目录下文件及目录的详情 1.第一位文件类型 普通文件 &#xff0c; d 目录文件&#xff0c;I 链接文件&#xff0c;p 管理文件&#xff0c; b 块设备文件&#xff0c; c 字符设备文件&#xff0c; s 套接字文件 2.文件属性 第一部分表示文…