错误分析、定位

在项目中使用到了数据库集群,使用时发现项目运行并且没有操作数据库一段时间之后再次操作数据库就会控制台出现以下报错。

Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@de1855 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.

项目整合mysql集群的时候使用的是苞米豆开发的动态数据源工具。

     <!--动态数据源,提供@DS注解方便使用动态数据源--><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>2.5.4</version></dependency>

看日志大概知道是连接池的错误,使用的是hikari数据库连接池。之前只知道druid没了解过hikari,在整合动态数据源工具的时候也没有配置相关的连接池。报错内容里建议我们使用小一些的maxLifetime值,所以很可能这个报错的原因是连接池的参数maxLifetime大于数据库的连接lifetime,连接池里的连接没过期,但数据库那边已经过期了,然后 operations after connection closed了。

mysql连接超时参数

mysql有关连接超时的参数有两个,一个是interactive_timeout 另一个是wait_timeout ,单位都是s
使用以下语句查看

show variables like '%timeout%';


这两个参数默认都是28800s,即8个小时;
其中interactive_timeout指的是mysql在关闭一个交互的连接之前所要等待的秒数 ;wait_timeout指的是mysql在关闭一个非交互的连接之前所要等待的秒数。通过mysql客户端连接数据库是交互式连接,通过jdbc连接数据库是非交互式连接。

HikariCP连接超时参数

Druid和HikariCP是处于活跃状态数据库连接池,据说更简单更快。但本文关注其连接超时参数。


查看源码以及官方文档得知
CONNECTION_TIMEOUT 是等待来自池的连接的最大毫秒数,默认30000ms,也就是30秒。至少是250 ms。
IDLE_TIMEOUT是连接允许在池中闲置的最长时间,默认600000ms,也就是10分钟。这个值至少是10 秒,0代表无限。这个值只在设置了minimumIdle 时才有效。
MAX_LIFETIME是池中连接最长生命周期,默认1800000 ms,也就是30分钟。这个值至少是30 秒,0代表无限。
这些值都远远小于mysql的8小时

官方文档对于maxlifetime提到

We strongly recommend setting this value, and it should be several seconds shorter than any database or infrastructure imposed connection time limit

强烈建议我们将这个值设置为数据库连接超时的值短几秒。

超时时间的机制

长时间没有使用该Connection,Connection会被Mysql关闭(但不为null)。此时调用该Connection时就会抛出异常。
但是按道理来说,mysql那边8小时过期,而数据库连接池30分钟,不应该会出现这种问题的,并且这种问题出现在几十秒内。

使用命令查看目前的连接

SHOW PROCESSLIST;


发现存活着大量的连接,大约有三四十个,应该是之前程序启动留下来的一些连接,mysql这边并没有关闭连接,是连接池的问题。

那还是hikari的配置问题,只好按照提示试着改一下max-lifetime
如果没有使用动态连接库可以使用一下配置。

spring:datasource:hikari:max-lifetime: 300000

由于使用的是动态连接库,所以这个hikari要在其配置下配置。

spring:datasource:dynamic:datasource:hikari:max-lifetime: 300000

改为800000在闲置五分钟后发送请求能够稳定触发报错,而当设置为30000时,则再也没出现错误了。此时mysql数据库的wait_timeout还是为8小时。
将wait_timeout改为了300秒,即和以上的修改一样,都是五分钟。修改之后大量的连接消失了,然后重启项目的时候发现启动时就有四个连接,他们的time值最大不超过300,超过了就会从0开始数起,这个值受max-lifetime制约,随着后面的请求次数增多,连接就增多,但最终固定在10个连接。这10个连接受的是hikari的最大线程数制约,由于没有设置闲置等待时间以及闲置线程数,所以大概这个程序运行期间一直都是10个连接,而当我退出程序之后,超过time超过300的连接会直接消失,不再从0开始数起。

这里有个非常绕的一点就是wait_timeout和interactive_timeout 。
mysql有两个级别的配置,一个是session,另一个是global。下买面这个语句默认是session级别:

show variables like '%timeout%';

如果要看mysql的global级别需要加global参数:

show global variables like '%timeout%';

这两个级别下一共有四个参数:

  • global级别的interactive_timeout
  • global级别的wait_timeout
  • session级别的interactive_timeout
  • session级别的wait_timeout

对于各个参数作用的详细实验过程可以看这个帖子,但是看得实在让人头晕。这里我总结一下,有一下几条需要注意的:

  1. 在交互模式下,session级别的 interactive_timeout 继承了global级别 interactive_timeout 。
  2. 在交互模式下,连接时长受interactive_timeout 影响。
  3. 在非交互模式下,session级别的wait_timeout ,继承了global级别wait_timeout 。
  4. 在非交互模式下,连接时长受wait_timeout 影响。
  5. 在交互模式下,session级别的wait_timeout ,继承了global级别interactive_timeout。
  6. global级别的值修改对后续的连接有效,session级别的值对当前连接有效。
  7. 相同等级下的参数互不影响。

有人一第五条得出结论:要修改wait_timeout还要同时修改global级别的interactive_timeout。
原因是他们一直查看和修改session级别的配置,但是这并没有什么本文来说没有什么意义。
我们的目的是修改后续我们的连接池的连接(非交互模式)的超时时间,也就是希望后续的session级别的wait_timeout的值是我们的设置的值。根据第三条规则可以知道,这时候我们设置global级别的wait_timeout就可以了。

set global wait_timeout=300;

了解清楚了mysql的timeout机制就不难明白,global级别的wait_timeout对应的就是maxlifetime,为了防止网络延迟导致maxlifetime没过期时发送请求,到达mysql时wait_timeout刚好过期,所以要将maxlifetime要设置的比maxlifetime小几秒。至于为何之前8小时的wait_timeout和30分钟的maxlifetime会在大概5分钟左右丢失连接,这个一时半会儿还弄不明白,先这么配置先吧。

HikariCP连接池:Possibly consider using a shorter maxLifetime value.相关推荐

  1. HikariCP连接池配置

    2019独角兽企业重金招聘Python工程师标准>>> HikariCP号称性能最好的Java数据库连接池.虽没做过亲测但是公司项目一直在用,大概经历过2万左右用户同时在线,链接池性 ...

  2. mysql api 连接池_SpringBoot-整合HikariCP连接池

    HikariCP连接池概述池化思想 池化思想是我们项目开发过程中的一种非常重要的思想,如整数池,字符串池,对象池.连接池.线程池等都是池化思想的一种应用,都是 通过复用对象,以减少因创建和释放对象所带 ...

  3. springboot整合mybatis 使用HikariCP连接池

    springboot整合mybatis 使用HikariCP连接池 前言 Springboot让Java开发更加美好,本节主要讲的是使用Hikari数据库连接池,如果需要使用druid连接池的请看我另 ...

  4. DBCP,C3P0,druid,HiKariCP连接池配置使用

    Apache DBCP连接池配置 Apache commons-dbcp 需要导入dbcp包和 pool包 ,可以 从spring-framework-3.0.2.RELEASE-dependenci ...

  5. Spring Boot 使用 HikariCP 连接池配置详解

    Spring Boot 使用 HikariCP 连接池配置详解 HikariCP 是一个高性能的 JDBC 连接池组件. Spring Boot 2.x 将其作为默认的连接池组件,项目中添加 spri ...

  6. HikariCP连接池8小时后只有一个连接或session问题

    项目中的一个批处理程序,需要长时间与数据库保持连接,属于典型的"写多读少"场景.监控的结果发现程序前8小时性能很好,之后就开始衰减. 用 show full process lis ...

  7. HikariCP连接池教程

    HikariCP连接池已作为当前流行的SpringBoot框架默认连接池,那如何在一个非框架服务使用HikariCP? HikariCP官方地址:https://github.com/brettwoo ...

  8. 在 Spring Boot 中使用 HikariCP 连接池

    上次帮小王解决了如何在 Spring Boot 中使用 JDBC 连接 MySQL 后,我就一直在等,等他问我第三个问题,比如说如何在 Spring Boot 中使用 HikariCP 连接池.但我等 ...

  9. hikaricp和mysql驱动_配置HikariCP连接池

    配置HikariCP连接池 数据库配置 spring.datasource.driver-class-name=com.mysql.jdbc.Driver 指定 spring 连接数据源驱动 spri ...

最新文章

  1. 从中科院到BAT,如何准备秋招那件事儿(附B站录播)
  2. c++ array容器 传参_华东理工:氮和氧共掺杂的分级多孔碳,用于超级电容器的电极材料...
  3. 学习换脸:Switching Eds: Face swapping with Python, dlib, and OpenCV
  4. mysql 存储中文问题
  5. php有哪些开源社区,PHP开源社区
  6. php 返回object,深入分析使用mysql_fetch_object()以对象的形式返回查询结果
  7. 二叉树学习之二叉树的构建及操作
  8. fgetc和fputc函数
  9. ibmx系列服务器装系统,IBM X系列服务器 系统安装指南.pdf
  10. (三)IDEA部署Tomcat原理
  11. 呼吸机吸气触发:压力触发与流量触发
  12. 最优化理论与方法学习笔记01——黄金分割法与进退法求单峰区间Matlab编程实现
  13. 征文 | 青出于蓝而胜于蓝 国货之光GBase
  14. oracle授予directory读权限,Oracle对目录文件(directory)的读写操作
  15. dedeCMS采集插件自动采集文章自定义接口
  16. SSH Remote forwarding的示例
  17. 将.pyc反编译成.py
  18. 开发 mirai QQ机器人起步教程
  19. MongoDB Ubuntu安装 APP 支付宝微信支付
  20. O2OA RCE 远程命令执行漏洞复现(CVE-2022-22916)

热门文章

  1. 网络设置巨形帧_网络 – 升级到千兆网络 – 启用巨型帧
  2. jenkins恢复assign roles
  3. PHP知识一:系统知识总结
  4. Fiddler的下载与基本使用方法
  5. 如何给IBM X3650 M4 安装CentOS8.3.2011
  6. 卧槽!我用Python做一个打字测试器!看看谁是最快的男人!
  7. 【小白笔记】常见网页访问状态码及网页请求
  8. esxi显卡给2个虚拟机_使用虚拟机ESXI,显卡直通VM,使一台实体机虚拟成HTPC、WEB服务器、NAS服务器等经验 - 小众知识...
  9. MySQL——数据库基本操作(教程)
  10. 某游戏彩票外企Java面试题