一次数据库查询超时优化问题的实战记录
作者:丽大佬的小跟班 发布时间:2024-01-25 18:03:11
问题发现
在七月份时,经常发现有几个定时任务报错,查看了下异常原因,大概定位是数据库执行异常
### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Unsupported command
### The error may exist in class path resource [mapper/XXXXXXXXX-Mapper.xml]
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: select t3.cino, t2.sn as orderSn, t2.provider_id as providerId, t4.logistics_no as logisticsSn, t2.`name`,
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Unsupported command
; Unsupported command; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Unsupported command
org.springframework.dao.DataAccessResourceFailureException:
### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Unsupported command
### The error may exist in class path resource [mapper/XXXXXXXXXOMapper.xml]
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: select t3.cino, t2.sn as orderSn, t2.provider_id as providerId, t4.logistics_no as logisticsSn,
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Unsupported command
查找原因
1 和 DBA 排查 mycat(公司使用 mycat ) 和 mysql 的错误日志。发现是应用服务这边会给 MyCat 发送一个 KILL QUERY 命令,而 myCat 不支持该 KILL QUERY 命令。才给应用服务返回了 Unsupported command 异常错误
2021-07-02 10:46:33.567 WARN [$_NIOREACTOR-37-RW] (io.mycat.server.ServerQueryHandler.query(ServerQueryHandler.java:96)) - Unsupported command:KILL QUERY 2956587
2 上网搜索了下 KILLQUERY 发生的场景,在一篇文章 深入分析JDBC超时机制 找到问题所在,sql 执行超时,jdbc 会向 mysql 服务发送一个kill 命令,从而让 mysql 停止 sql 执行。不过传给了 mycat 服务,mycat 没有处理该命令,而是直接报错返回
3 查看了下应用服务的配置,在 jdbc:url 统一配置的 mysql socket 执行超时时间是 15s。而在 mybatis 单独的 sql 执行语句配置的设置更长,是 20s(注意这里的配置是 xml 加 注解的方式)
3.1 mybatis xml里的 sql 语句我单独在客户端执行,测试的 sql 执行时间大概在 6,7 秒左右,是不会超过 15s 这个限制的,但是从定时任务调度日志看,每次任务总体上就执行了 8 秒左右,说明 mycat 确实是在15秒内收到超时 KILL 命令,从而导致sql 执行失败
4 想着是不是在其他地方配置超时。细看了下 mybatis 的配置,还真有一个统一 sql 超时配置,default-statement-timeout = 5
从mybatis 源码文档上看,单独设置的 mybatis @Options timeout属性是会覆盖掉在 yml 配置的 default-statement-timeout属性的。难道是 @Options 没生效 ?
5 因此决定本地调试一波。发现 @Options 还真的没生效,jdbc的 queryTimeout 取值的是 mybatis在yml的 全局配置
解决问题
上面提到, sql 的 statment 混合使用了 mybatis 的注解和xml混合使用。猜测应该是 mybatis 的 注解和xml 使用方式是不兼容的。因此试着在 xml 的 statment 修改了 timeout配置。设置 timeout = 60。发现 配置生效了,如下图
后面也试着将 sql 放置到 mybatis 的 @Select 注解,去掉 xml 的 statement。@Options 的配置也是可以生效的。mybatis 的@Options 和 xml 是无法同时生效的,可能 mybatis 其他的注解一样和 xml 配置不能同时生效,希望读者以后能避开这个坑
额外话:Transaction Timeout、Statement Timeout、Socket timeout 的区别
上面 mybatis 配置的 timeout 其实就是Statement Timeout。还有就是在jdbc:url 配置的socketTimeout;其实还有是spring定义的一个事务超时: Transaction Timeout
它们三者的关系是在怎样的呢
Statement Timeout
statement timeout 是用来限制一条语句 statement 的执行时长,可通过调用JDBC的java.sql.Statement.setQueryTimeout(int timeout) 进行设置,不过一般是通过ORM框架来进行设置
在 myBatis中,statement timeout 的默认值是通过 defaultStatementTimeout 属性进行设置。同时还可以在 xml 中 select,insert,update标签设置timeout属性,从而对不同 sql 语句配置超时时间
Transaction Timeout
Spring 提供的 transaction timeout 配置也非常简单,它会记录每个事务的开始时间和消耗时间,当超出timeout值时将抛出异常。
假设某个事务中包含 3 个statement,每个statement的执行时间是 100ms,其他业务逻辑的执行时间是 50ms,那么transaction timeout至少应该设置为350ms(100 * 3 + 50)
Socket timeout
JDBC的 socket timeout 在数据库被突然停掉或是发生网络错误时十分重要。由于TCP/IP的结构原因,socket没有办法探测到网络错误,因此应用也无法主动发现数据库连接断开。如果没设置 socket timeout 的话,应用在数据库返回结果前会无期限地等下去,这种连接被称为 dead connection
优先级顺序
Socket timeout 级别优于 Transaction Timeout,而Transaction Timeout 级别优于 Statement Timeout。也就是说如果 Statement Timeout 大于 Transaction Timeout 或者 Socket timeout,则无法生效
不推荐使用socket timeout来限制statement的执行时长,因此socket timeout的值必须要高于statement timeout,否则,socket timeout将会先生效,这样statement timeout就变得毫无意义
参数文章
深入分析JDBC超时机制
如何配置MySQL数据库超时设置
来源:https://www.cnblogs.com/cscw/p/15398573.html
猜你喜欢
- 人工智能是一个很广阔的领域,很多编程语言都可以用于人工智能开发,所以很难说人工智能必须用哪一种语言来开发。选择多也意味着会有优劣之分,并不是
- 1. MySQL的安装与配置:在Ubuntu下安装MySQL方法很简单,使用如下命令:sudo apt-get install mysql-
- 本文实例总结了php处理json格式数据的方法。分享给大家供大家参考,具体如下:1.json简介:何为json?简 单地说,JSON 可以将
- 1.背景1.1. 项目介绍golang/sync库拓展了官方自带的sync库,提供了errgroup、semaphore、singlefli
- MySQL数据库由于它本身的小巧和操作的高效, 在数据库应用中越来越多的被采用.本文中列举了一个P2P应用开发实例,实例中使用了MySQL来
- 模板在写动态页面的网站的时候,我们常常将不变的部分提出成为模板,可变部分通过后端程序的渲染来生成 * 页,golang提供了html/tem
- 第一步:创建一个表。 create table Test_Table ( ID number(11) primary key, Name v
- def Num2MoneyFormat( change_number ): ""&q
- 计算机视觉方面朋友都需要跟图像打交道,在pytorch中图像与我们平时在matlab中见到的图像数据格式有所不同。matlab中我们通常使用
- 如何解决pycharm配置跨域不提示?正常我们需在在如上中间件内配置跨域,但是2019之前的版本配置中间件可能需要全部自己敲出来,不会有提示
- 区别:xx:公有变量,所有对象都可以访问;xxx:双下划线代表着是系统定义的名字。__xxx:双前置下划线,避免与子类中的属性命名冲突,无法
- reflow是个神奇的东西,之前Realazy说到过这个reflow,我摘出其中的重点:在CSS规范中有一个渲染对象的概念,通常用一个盒子(
- 我们或多或少都使用过各式各样的富文本编辑器,其中有一个很方便功能,复制一张图片然后粘贴进文本框,这张图片就被上传了,那么这个方便的功能是如何
- 1、一些准备工作 安装djangopip install django创建django项目进入项目代码存放目录执行命令:djang
- 如下所示:1.条件判断2.内置函数abs()3.内置模块 math.fabsabs() 与fabs()的区别abs()是一个内置函数,而fa
- 首先贴一张验证码上来做案例:第一步先通过二值化处理把干扰线去掉:from PIL import Image# 二值化处理def two_va
- 1 什么是嵌套循环所谓嵌套循环就是一个外循环的主体部分是一个内循环。内循环或外循环可以是任何类型,例如 while 循环或 for 循环。
- (1)int转strings := strconv.Itoa(i)等价于s := strconv.FormatInt(int64(i), 1
- 以下是Django框架获取各种form表单数据的方法Django中获取text,password名字:<input type
- 在Windows平台下,如果想运行爬虫的话,就需要在cmd中输入:scrapy crawl spider_name这时,爬虫就能启动,并在控