首页 > 其他分享 >“自以为对的”MyBatis空闲连接探测的机制

“自以为对的”MyBatis空闲连接探测的机制

时间:2023-06-19 12:03:33浏览次数:40  
标签:poolPingConnectionsNotUsedFor 默认值 探测 poolPingQuery SQL MyBatis 超时 连接 空闲


最近碰到个现象,某个应用,每天在21:00-23:00才会执行,连接数据库执行操作,间隔性出现连接超时的错误,

Connection timed out (Read failed)

因为应用和数据库是跨网段,咨询了下,防火墙超时时间配置的是30分钟,应用用的MyBatis连接池,相关配置如下,

“自以为对的”MyBatis空闲连接探测的机制_java

相关参数解释,如下所示,

POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。这种处理方式很流行,能使并发 Web 应用快速响应请求。

除了上述提到UNPOOLED下的属性外,还有更多属性用来配置POOLED的数据源:

poolMaximumActiveConnections – 在任意时间可存在的活动(正在使用)连接数量,默认值:10

poolMaximumIdleConnections – 任意时间可能存在的空闲连接数。
poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
poolTimeToWait – 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。
poolMaximumLocalBadConnectionTolerance – 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过 poolMaximumIdleConnections 与 poolMaximumLocalBadConnectionTolerance 之和。默认值:3(新增于 3.4.5)
poolPingQuery – 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。
poolPingEnabled – 是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。
poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。

P.S. 

https://mybatis.org/mybatis-3/zh/configuration.html#environments

按照这字面意思,一开始我们理解poolPingConnectionsNotUsedFor参数控制的是连接多久没用,即处于空闲状态,在参数poolPingEnabled开启时,就会执行poolPingQuery定义的SQL主动探测。

如果按照这理解,poolPingConnectionsNotUsedFor设置了3000,即3秒,远小于30分钟防火墙超时的设置,不应该出现连接超时的现象。

我们怀疑过防火墙的配置,但从应用端看,并不是所有的请求都超时,而且防火墙端,没看到什么异常。数据库层,应该未设置过相关的配置。

原因是什么?

作为一款成熟的产品,不太可能因为bug,更多还是对他的理解存在偏差。

下载3.3.0的源码,链接如下,

https://github.com/mybatis/mybatis-3/releases/tag/mybatis-3.3.0

搜索这几个参数所在的文件,找到了PooledDataSource类,可以看到这三个参数都设置了初始值,

“自以为对的”MyBatis空闲连接探测的机制_数据库_02

看下这个pingConnection方法,

“自以为对的”MyBatis空闲连接探测的机制_编程语言_03

如果连接未关闭,判断逻辑如下,

1. poolPingConnectionsNotUsedFor的值>=0;

2. getTimeElapsedSinceLastUse()>poolPingConnectionsNotUsedFor;

getTimeElapsedSinceLastUse()定义如下,

“自以为对的”MyBatis空闲连接探测的机制_mysql_04

lastUsedTimestamp是在构造函数PooledConnection中定义的,

“自以为对的”MyBatis空闲连接探测的机制_分布式_05

PooledConnection会在获取连接(popConnection)和回收连接(pushConnection)的时候调用,获取连接和回收连接则会被getConnection()和invoke()调用,因此,(2)的意思是当前这个连接空闲的时间是否大于这个参数poolPingConnectionsNotUsedFor定义的时间。

3. 如果满足条件(1)和(2),则会执行poolPingQuery的SQL,此处就是"select 1 from dual",如果执行失败,会关闭这个连接,

“自以为对的”MyBatis空闲连接探测的机制_分布式_06

从应用日志,能看到这些信息,

Testing connection 0000000000 ...
Execution of ping query 'select 1 from dual' failed:  Connection timed out (Read failed)

这个问题的关键,就是这个pingConnection,在什么时候调用,就决定了poolPingConnectionsNotUsedFor什么时候起作用,可以看到,他是在这个isValid的方法中调用的,

“自以为对的”MyBatis空闲连接探测的机制_数据库_07

而这个isValid是在每次获取连接和回收连接时调用的,换句话说,他是被动调用,并不是我们认为的空闲时主动调用,所以这个应用,只是晚上会跑,空闲连接超过30分钟是很正常的,

“自以为对的”MyBatis空闲连接探测的机制_分布式_08

应用开了debug,这两段之间的间隔时间,就是得到超时连接的时间,

“自以为对的”MyBatis空闲连接探测的机制_mysql_09

经过单线程测试,大约在15分钟,

“自以为对的”MyBatis空闲连接探测的机制_mysql_10

因此,对这种testOnBorrow的连接探测机制,各有优缺点,优点就是会在一定程度保证应用正常的业务请求得到可用的连接,毕竟不可用的连接都已经被poolPingQuery定义的SQL测试了,一般情况下,不会让正常的业务请求出现报错,除非连接池没任何可用的连接。缺点就是如果配置的poolPingConnectionsNotUsedFor很小,某些请求都会在执行之前先进行验证,但是换个角度,如果是高并发,只要参数不是0,一般可能都不会满足需要验证的条件,如果设置为0,就可能会有很多pingQuery定义的SQL执行。而且,如果像上述单线程的操作,他会一个连接一个连接的尝试,等待一个连接出现超时错误的时间间隔是15分钟,这就很低效了。

对连接池的选择和配置,确实得结合实际场景需求来决策。

通过这个问题,至少让我明白,“自以为对的”机制正确还是错误,还是看他的实现,这才是最可靠的验证,而且,通过他的逻辑,可以让我们借鉴一些设计路径,多考虑他这么做背后的意义和影响,更有助我们将其用到正确的场景。

标签:poolPingConnectionsNotUsedFor,默认值,探测,poolPingQuery,SQL,MyBatis,超时,连接,空闲
From: https://blog.51cto.com/u_13950417/6512313

相关文章

  • mybatis-plus 数据库日志仅打印SQL
     一、项目背景:springboot、web组件、Mysql8、java8+; 二、开发环境打印SQL及执行结果日志,便于调试接口;mybatis-plus配置文件的configuration节点添加以下配置2、效果   三、生产环境仅打印SQL,避免打印过多的查询结果影响系统性能    1、pom中增加sl4j的......
  • mybatis plus generate
    1.添加依赖<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><dependency>......
  • 01 MyBatis第一个应用程序
    1、MyBatis是什么?mybatis是一个基于java的持久层框架。2、什么是持久化数据由瞬态状态变为持久状态。3、持久层:完成持久化工作的代码块。--DAO层,将数据存到数据库4、MyBatis就是帮助程序员将数据存入数据库中,和从数据库中取数据。5、传统JDBC操作:有很多重复代码块,比如:数......
  • MybatisPlus自动填充
    importcom.baomidou.mybatisplus.core.handlers.MetaObjectHandler;importlombok.extern.slf4j.Slf4j;importorg.apache.ibatis.reflection.MetaObject;importorg.springframework.stereotype.Component;importjava.time.LocalDateTime;@Slf4j@Componentpublic......
  • MybatisPlus拦截器配置
    /***配置mp的分页插件(拦截)*/@ConfigurationpublicclassMybatisPlusConfig{@BeanpublicMybatisPlusInterceptormpInterceptor(){MybatisPlusInterceptormybatisPlusInterceptor=newMybatisPlusInterceptor();mybatisPlusInterceptor.......
  • Mybatis
    MyBatis1、Mybatis简介1.1、什么是MyBatis**持久层框架**避免了几乎所有的JDBC代码和手动设置参数以及获取结果集的过程可以使用简单的XML或注解来配置和映射原生信息,将接口和Java的实体类【PlainOldJavaObjects,普通的Java对象】映射成数据库中的记录。Myba......
  • MyBatis Plus
    MyBatisPlus是MyBatis的增强工具,它简化了MyBatis的使用,提供了更多的功能和特性,让开发者更加方便地进行数据库操作。本文将介绍MyBatisPlus的一些技术特点和使用方法。1.MyBatisPlus的技术特点MyBatisPlus的技术特点主要有以下几个方面:(1)简化开发:MyBatisPlus提供了很多常用......
  • 通用mapping实现的SSM项目:SSM 框架:是 Spring + Spring MVC + MyBatis
    1.结合通用mapping实现的SSM项目:SSM框架:是Spring+SpringMVC+MyBatis的缩写mybatisgenerator:配置插件通用mapper:tk.mybatis2.MyBatis逆向工程组件是MyBatisGenerator,简称MBG,是专为MyBatis框架制定代码自动生成解决方案,MBG可以根据数据表结构快速生成对应的实体类、......
  • Mybatis-plus的selectPage()分页查询不生效问题
    @Configuration@MapperScan("com.wl.spbt_vue.mapper")publicclassMybatisPlusConfig{@BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(){MybatisPlusInterceptorinterceptor=newMybatisPlusInterceptor();inte......
  • mybatis 3.x 升级时遇到的keyProperty问题小坑
    背景:有1个项目,原来是用的mybatis3.4.6版本,其中有一些插入mapper是这样写的:IntegerinsertEntitySelectiveShard(@Param("tableSuffix")StringtableSuffix,@Param("entity")XXXEntityentity);对应的xml片段:<insertid="insertEntitySelectiveShard"par......