如何解决MySQL死锁(看懂MySQL锁日志)

有时候系统在生产运行着,会突然爆出

[40001][1213] Deadlock found when trying to get lock; try restarting transaction

这个时候每个人都会很紧张,因为死锁会影响DB性能,严重时甚至拖垮整个系统。在实际的环境中,很多服务会共用一个数据库,一旦数据库挂了,基本就是P0事故。

那么,死锁发生时,我们如何定位到死锁发生的SQL?

死锁排查

实操前置准备

磨刀不误砍柴功,我们先准备下实验环境。

首先创建一张表:

create table users(id int comment "id",age int comment '年龄',id_no int comment '身份证号',UNIQUE KEY `uk_task_obj` (`id_no`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='用户表';

写入数据:

insert into users values (1,18,1);
insert into users values (2,18,2);
insert into users values (3,18,3);

接着,我们开两个事务:

事务一:

begin;
select * from users where id_no=1 for update;
select * from users where id_no=3 for update ;
commit;

事务二:

begin;
select * from users where id_no=3 for update ;
select * from users where id_no=1 for update ;
commit ;

可以看到,两个事务执行的语句都一样,只不过顺序不一样,我们按照以下时序去执行时,终端会提示Deadlock found when trying to get lock; try restarting transaction

事务一事务二

beigin;

select * from users where id_no=1 for update;

begin;

select * from users where id_no=3 for update ;
select * from users where id_no=3 for update ;
select * from users where id_no=1 for update ;(此时死锁发生)

查看日志

要定位死锁发生的原因,我们需要知道,是哪些事务持有了哪些锁,哪些事务又互相阻塞。

我们可以通过

SHOW ENGINE INNODB STATUS;

来查看死锁发生时的日志

日志分析

当执行SHOW ENGINE INNODB STATUS时,MySQL返回如下日志:

日志内容很多,我们主要关注:LATEST DETECTED DEADLOCK 这一部分。我们逐步讲解下这一部分的日志。

日志解释

LATEST DETECTED DEADLOCK

------------------------

2024-03-18 21:07:00 0x16be8b000

*** (1) TRANSACTION:

TRANSACTION 1836, ACTIVE 10 sec starting index read

TRANSACTION 1836:1836代表事务id;

active 10 sec:表示活跃时间

LOCK WAIT 4 lock struct(s), heap size 1128, 3 row lock(s)

MySQL thread id 17, OS thread handle 6121680896, query id 2044 localhost 127.0.0.1 root statistics

不重要,忽略

/* ApplicationName=GoLand 2023.2.2 */ select * from users where id_no=3 for update

这个事务执行的sql语句

*** (1) HOLDS THE LOCK(S):

RECORD LOCKS space id 2 page no 5 n bits 72 index uk_task_obj of table `test`.`users` trx id 1836 lock_mode X locks rec but not gap

Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0

 0: len 4; hex 80000001; asc     ;;

 1: len 6; hex 000000000200; asc       ;;

HOLDS THE LOCK:表示当前事务持有的锁。

RECORD LOCKS:表明是记录锁

space id 2 page no 5 n bits 72 :这是mysql底层存储的位置,我们可以不理解。

index uk_task_obj of table `test`.`users` trx id 1836 lock_mode X locks rec but not gap:表明是索引uk_task_obj上的锁。X锁代表互斥锁,rec but not gap表示是记录锁不是间隙锁。

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 2 page no 5 n bits 72 index uk_task_obj of table `test`.`users` trx id 1836 lock_mode X locks rec but not gap waiting

Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0

 0: len 4; hex 80000003; asc     ;;

 1: len 6; hex 000000000202; asc       ;;

WAITING FOR THIS LOCK TO BE GRANTED:这句话就说了,这个事务在等待索引uk_task_obj上的一个记录锁,下面是等待的锁信息。

*** (2) TRANSACTION:

TRANSACTION 1837, ACTIVE 7 sec starting index read

mysql tables in use 1, locked 1

LOCK WAIT 4 lock struct(s), heap size 1128, 3 row lock(s)

MySQL thread id 18, OS thread handle 6120566784, query id 2058 localhost 127.0.0.1 root statistics

/* ApplicationName=GoLand 2023.2.2 */ select * from users where id_no=1 for update

第一个事务在等待锁,这个时候提到第二个事务了。事务id是1837,执行的语句是select * from users where id_no=1 for update

*** (2) HOLDS THE LOCK(S):

RECORD LOCKS space id 2 page no 5 n bits 72 index uk_task_obj of table `test`.`users` trx id 1837 lock_mode X locks rec but not gap

Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0

 0: len 4; hex 80000003; asc     ;;

 1: len 6; hex 000000000202; asc       ;;

1837事务持有的锁也是记录锁,也是在唯一索引uk_task_obj上。

锁的信息如下:

0: len 4; hex 80000003; asc     ;;

 1: len 6; hex 000000000202; asc       ;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 2 page no 5 n bits 72 index uk_task_obj of table `test`.`users` trx id 1837 lock_mode X locks rec but not gap waiting

Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0

 0: len 4; hex 80000001; asc     ;;

 1: len 6; hex 000000000200; asc       ;;

WAITING FOR THIS LOCK TO BE GRANTED:等待锁

Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0

 0: len 4; hex 80000001; asc     ;;

 1: len 6; hex 000000000200; asc

等待一个记录锁,可以看到,事务1836和1837持有和等待的锁是相反的,因而发生死锁

*** WE ROLL BACK TRANSACTION (2)

MySQL选择回滚第二个事务

常见的MySQL死锁场景

上面的例子,是最常见的由于select for update产生的死锁问题,以下还有几种发生死锁的场景。

批量update

例如:insert into users values(1,2,3),(2,2,3),(3,3,3)和insert into users values(3,2,3),(2,2,3),(1,3,3)同时执行时,会由于锁的冲突会导致死锁。表面是看insert into users values(1,2,3),(2,2,3),(3,3,3)是一条语句,实际上MySQL并不是一次性加完全部锁,它会按照SQL的书写顺序逐步加锁。解决方法是在批量插入之前,我们按一定规则排序,只要两条sql按相同的顺序加锁便不会有死锁问题

update退化为共享锁

在MySQL中,update语句加的是排它锁,也就是X锁。如果此时另外一个事务正在执行select语句,对同一个目标加了共享锁之后,执行update的事务会由于加X锁失败,转而变为共享锁。

此时会发生如下情况:

事务1执行完第一步之后,已经持有A的共享锁;

事务2执行第二步,由于排它锁加锁失败,转为持有A的共享锁,同时等待事务1释放共享锁;

事务3执行第三步,要将共享锁升级为排它锁,等待事务2释放共享锁。

此时事务1和2发生了循环等待,导致死锁发生。

总结:

  1. 通过SHOW ENGINE INNODB STATUS查看MySQL死锁日志
  2. select for update是最常见的死锁场景
  3. 批量update时注意加锁顺序、小心update的排它锁退化成共享锁导致死锁发生

诚意满满系列每一篇都是精挑细选,从大众知识点到原理再到具体实现,争取把一个知识点从头到尾完整讲下来,足以应付面试与工作。让读者读完之后能够有一种:“这个知识我看这一篇就够了”的感觉是本系列最大愿望。

对于本人而言,在之前的学习中也发现,八股文讲得细致但不系统,而系统的学习往往又宽泛不细致,所以也打算取长补短,互相结合一下,欢迎大家收藏关注,持续更新。

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

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

相关文章

代码学习记录23--回溯算法第四天

随想录日记part23 t i m e : time: time: 2024.03.19 主要内容:回溯算法在代码学习中尤其重要,所以今天继续加深对其的理解:1:复原IP地址 ;2.子集 ;3.子集II 93.复原IP地…

shopee无货源出单了怎么发货?shopee怎么做无货源?

在Shopee的电商大舞台上,“无货源出单”就像是一场神奇的魔术表演。你的店铺是舞台,买家的订单是观众的掌声,而你,就是那位神秘的魔术师。订单来了,你却没有货?这可不是什么障碍,因为你有着更为…

前端学习从0到1:再见HTML(1)

阅读须知: 探索者安全团队技术文章仅供参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作,由于传播、利用本公众号所提供的技术和信息而造成的任何直接或者间接的后果及损失,均由使用者 本人负责,作者不为此承担任何责任,如…

AI系统性学习05—向量数据库

文章目录 1、Chroma向量数据库1.1 安装Chroma1.2 初始化Chroma客户端1.3 创建一个合集1.4 添加数据1.5 查询数据1.6 持久化数据1.7 集合操作1.7.1 创建集合1.7.2 获取集合1.7.3 删除集合1.7.4 其他操作1.8 向集合添加数据1.9 查询集合数据1.10 更新集合数据1.11 删除集合数据1.…

基于51单片机智能鱼缸控制系统

一、系统方案 1、本设计采用51单片机作为主控器。 2、液晶1602显示。 3、采集温度值,水质大小、水位值、DS1302显示年月日时分秒。 4、自动加热、定时喂食,自动换水、水泵加热。 5、按键设置。 二、硬件设计 原理图如下: 三、单片机软件设…

【教学类-44-08】20240319 “(幼儿用)数字练习簿1.0”(A4版)

背景需求: 我一直想把 “(幼儿用)数字练习簿”的内容复刻出来——这里面的字体始终找不到,是一种已经做成图片的手写数字字体 素材准备: 1、买了一本(幼儿用)数字练习簿,把每一页扫…

网络编程:多点通信+域套接字

一、多点通信 1.网络属性 getsockopt和setsockopt int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 功能:获取或设置套接字…

SSH服务

目录 一. 熟悉SSH服务 1.1 何为SSH协议 1.2 SSH服务优点 1.3 常见的SSH协议 1.4 SSH服务的功能 1.5 为何使用SSH服务 1.6 SSH服务的工作原理 1.6.1 公钥传输原理 1.6.2 ssh加密通讯原理 1.7 SSH服务的最佳应用场景 1.8 SSH服务远程登录的方式 1.8.1 方法一&#…

自动驾驶决策 - 规划 - 控制 (持续更新!!!)

总目录 Frenet与Cartesian坐标系 Apollo基础 - Frenet坐标系 车辆模型 车辆运动学和动力学模型 控制算法 PID控制器轨迹跟随实现 Pure Pursuit控制器路径跟随 路径跟踪算法Stanley 实现 c 无人驾驶LQR控制算法 c 实现 MPC自动驾驶横向控制算法实现 c 双环PID控制详细讲解 …

【DL经典回顾】激活函数大汇总(二十六)(Identity附代码和详细公式)

激活函数大汇总(二十六)(Identity附代码和详细公式) 更多激活函数见激活函数大汇总列表 一、引言 欢迎来到我们深入探索神经网络核心组成部分——激活函数的系列博客。在人工智能的世界里,激活函数扮演着不可或缺的…

大模型面试题最全总结,没有一道是送分题。。。

节前,我们组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂同学、参加社招和校招面试的同学,针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 今天分享…

3月19日做题

[NPUCTF2020]验证🐎 if (first && second && first.length second.length && first!second && md5(firstkeys[0]) md5(secondkeys[0]))用数组绕过first1&second[1] 这里正则规律过滤位(Math.) (?:Math(?:\.\w)?) : 匹配 …

优化器算法SGD、Adam、AdamW等

文章目录 SGDSGD with momentumSGD with Nesterov AccelerationAdaGradRMSpropAdaDeltaAdamAdamW参考资料 假设有: 待优化的目标函数为 f ( w ) f(w) f(w),使用优化算法来最小化目标函数 f ( w ) : a r g m i n w f ( w ) f(w):argmin_wf(w) f(w):argmin…

【Mysql】面试题汇总

1. 存储引擎 1-1. MySQL 支持哪些存储引擎?默认使用哪个? 答: MySQL 支持的存储引擎包括 InnoDB、MyISAM、Memory 等。 Mysql 5.5 之前默认的是MyISAM,Mysql 5.5 之后默认的是InnoDB。 可以通过 show engines 查看 Mysql 支持…

外包2月,技术退步惊现!大专生逆袭大厂,全靠这份神秘资料!

大家好,我是一名大专生,19年通过校招进入湖南某软件公司,从事功能测试工作已近4年。今年8月,我意识到长期舒适的环境让我变得不思进取,技术停滞不前,甚至因此失去了谈了2年的女朋友。我下定决心&#xff0c…

金蝶云星空——插件dll重新发布报错:鏃犳硶鏄剧ず椤甸潰锛屽洜涓哄彂鐢熷唴閮ㄦ湇鍔″櫒閿欒銆�

项目场景: 金蝶插件开发 问题描述 今天更新了插件dll然后重启IIS金蝶就报如下错误: 解决方案: 折腾了一天结果发现是给自己挖坑了,这次更新我担心插件代码有问题就把原dll重命名了然后把最新dll更新到金蝶bin文件中&#xff0c…

【DBC专题】-11-使用Cantools将CAN/CANFD DBC自动生成C语言代码

目录 1 安装Python和Cantools 1.1 查看Python已安装的Package包 1.2 在Python中安装Cantools插件包 1.3 获取更多Cantools工具的更新动态 2 经典CAN/CANFD DBC自动生成C语言代码 2.1 批处理文件CAN_DBC_To_C.bat内容说明 2.2 经典CAN/CANFD DBC文件要求 2.3 如何使用生…

网站引用图片但它域名被墙了或者它有防盗链,我们想引用但又不能显示,本文附详细的解决方案非常简单!

最好的办法就是直接读取图片文件&#xff0c;用到php中一个常用的函数file_get_contents(图片地址)&#xff0c;意思是读取远程的一张图片&#xff0c;在输出就完事。非常简单&#xff5e;话不多说&#xff0c;直接上代码 <?php header("Content-type: image/jpeg&quo…

clipboard好用的复制剪切库

clipboard是现代复制到剪贴板的工具&#xff0c;其 gzip 压缩后只有 3kb&#xff0c;能够减少选择文本的重复操作&#xff0c;点击按钮就可以复制指定内容&#xff0c;支持原生HTMLjs&#xff0c;vue3和vue2。使用方法参照官方文档&#xff0c;so easy&#xff01;&#xff01;…

装X神器,装X图片生成器,高富帅模拟器

先展示两张效果 基金装X图 短信存款图 神器功能展示 总共有12大类可供用户选择 还有一些美感的&#xff1a; 总结 总之种类非常多&#xff0c;有了这个神器你懂的&#xff5e; 关注下方公众号&#xff0c;回复【zzsq】即可获取。