一文教你学会定位线上MySQL锁超时问题
作者:一灯架构 发布时间:2024-01-22 13:19:45
前言:
昨晚我正在床上睡得着着的,突然来了一条短信。
什么?线上的订单无法取消!
我赶紧登录线上系统,查看业务日志。
发现有MySQL锁超时的错误日志。
不用想,肯定有另一个事务正在修改这条订单,持有这条订单的锁。
导致当前事务获取不到锁,一直等待,直到超过锁超时时间,然后报错。
既然问题已经清楚了,接下来就轮到怎么排查一下到底是哪个事务正在持有这条订单的锁。
好在MySQL提供了丰富的工具,帮助我们排查锁竞争问题。
现场复现一个这个问题:
创建一张用户表,造点数据:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(50) NOT NULL DEFAULT '' COMMENT '姓名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
事务1,更新id=1的用户姓名,不提交事务:
begin;
update user set name='一灯' where id=1;
事务2,删除id=1的数据,这时候会产生锁等待:
begin;
delete from user where id=1;
接下来,我们就通过MySQL提供的锁竞争统计表,排查一下锁等待问题:
先查一下锁等待情况:
select * from information_schema.innodb_lock_waits;
可以看到有一个锁等待的事务。
然后再查一下正在竞争的锁有哪些?
select * from information_schema.innodb_locks;
可以看到,MySQL统计的非常详细:
lock_trx_id 表示事务ID
lock_mode 表示排它锁还是共享锁
lock_type 表示锁定的记录,还是范围
lock_table 锁的表名
lock_index 锁定的是主键索引
再查一下正在执行的事务有哪些?
select * from information_schema.innodb_trx;
可以清楚的看到正在执行的事务有两个,一个状态是锁等待(LOCK WAIT
),正在执行的SQL也打印出来了:
delete from user where id=1;
正是事务2的删除语句。
不用问,第二条,显示正在运行状态(RUNNING)的事务就是正在持有锁的事务1,MySQL线程id(trx_mysql_thread_id
)是193。
我们用MySQL线程id查一下事务线程id:
select * from performance_schema.threads where processlist_id=193;
找到对应的事务线程id是218,然后再找一下这个线程正在执行的SQL语句:
select THREAD_ID,CURRENT_SCHEMA,SQL_TEXT
from performance_schema.events_statements_current
where thread_id=218;
可以清楚的看到这个线程正在执行的SQL语句就是事务1的update语句。
持有锁的SQL语句找到了,接下来再去找对应的业务代码也就轻而易举了。
以上是基于MySQL5.7版本,在MySQL8.0版本中有些命令已经删除了,替换成了其他命令,下篇文章再讲一下MySQL8.0怎么定位MySQL锁超时问题。
来源:https://juejin.cn/post/7128419961415925790


猜你喜欢
- 获取所有variable(每个op中可训练的张量)的name:for variable_name in tf.global_variable
- 在多线程的使用时,为了线程的顺利进行,我们会使用函数来对某个线程进行暂停运行。在多线程中有两个函数可以实现sleep和wait,不过它们在使
- 前言生成器generator生成器的本质是一个迭代器(iterator)要理解生成器,就要在理解一下迭代,可迭代对象,迭代器,这三个概念Py
- 一、程序运行1.效果展示 - 轮廓描绘看轮廓描绘效果:2.效果展示 - 颜色填充衣服和裤子颜色填充效果:二、实现过程1.绘图数据下载获取地址
- 网络连接与通信是我们学习任何编程语言都绕不过的知识点。 Python 也不例外,本文就介绍因特网的核心协议 TCP ,以及如何用 Pytho
- 问题1:如何获取caller的(文件名,行号,函数名)?当新增一条log记录时,最终将调用Logger类的_log方法,这个方法首先会创建一
- 以前在介绍SQL2k的时候已经提到了SQL2k对XML的支持,使用for XML语句就可以很容易的把执行的结果转化为一个XML,这样可以在很
- 引言人工智能是计算机科学中一个非常热门的领域,近年来得到了越来越多的关注。它通过模拟人类思考过程和智能行为来实现对复杂任务的自主处理和学习,
- 合理使用装饰器可以简化开发,并且使得代码更加清晰。下面我们分别介绍两种装饰器,不带参数的装饰器和带参数的装饰器。一、不带参数的装饰器我们用一
- 第一个示例: 简单的jsp自定标签获取内容: 首先创建一个jsp实例类然后继承SimpleTagSupport类 然后实现父类的doTag(
- 一、语法错误异常:大多数的异常都不会被程序处理,都以错误信息的形式展现在这里二、异常处理while True: t
- # -*- coding: utf-8 -*- #mysqldb &nb
- 本文实例讲述了MySQL 的启动和连接方式。分享给大家供大家参考,具体如下:MySQL运行包括两部分,一部分是服务器端程序mysqld,另外
- Ajax的流行给用户体验带来了很大程序的提升,而“注册“这项做为互联网最常用到的功能也自然而然的成为Ajax最常光顾的地方,实时判断用户输入
- 前言使用 webstrom 调试 Vue.js 单页面程序,理论上来说应该是支持所有用 webpack 构建的应用程序webstrom 版本
- Sys.path 指定用于模块搜索路径的字符串列表也可以通过sys模块的append方法在Python环境中增加搜索路径。Sys.path.
- 通过 Regsvr 32 .exe, 然后注册下列 DLL : C:\Program files\Common Files\System\A
- 为什么要 mock?后台接口还没完成,但前端要用到接口我想篡改后台接口的结果,测试一些分支逻辑起步本篇文章会使用到 swr、axios、vi
- 此命令作用,修改数据表ff_vod,在vod_url字段内容后加入999999999。update ff_vod set vod_url=C
- 如何向 pandas.DataFrame 添加新的列或行通过指定新的列名/行名来添加,或者用pandas.DataFrame的assign(