遇到 MySQL 死锁问题如何解决?

怎么解决 MySQL 死锁问题? 死锁是并发系统中常见的问题,同样也会出现在数据库MySQL的并发读写请求场景中。当两个及以上的事务,双方都在等待对方释放已经持有的锁或因为加锁顺序不一致造成循环等待锁资源,就会出现“死锁”。常见的报错信息为。举例来说 A 事务持有 X1 锁 ,申请 X2 锁,B事务持有 X2 锁,申请 X1 锁。A 和 B 事务持有锁并且申请对方持有的锁进入循环等待,就造成了死锁。如上图,是右侧的四辆汽车资源请求产生了回路现象,即死循环,导致了死锁。 阅读详情
AI摘要

本文深入解析MySQL InnoDB存储引擎中死锁的检测与解决机制,包括事务排序、权重计算、日志记录及事务回滚流程。

终于来到死锁检查线程的第三步,可以解决死锁了。

作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 MySQL 和 OceanBase 源码。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文基于 MySQL 8.0.32 源码,存储引擎为 InnoDB。

1. 选择死锁受害事务

前面介绍了死锁线程做的准备工作,以及发现死锁的过程。现在,是时候解决死锁了。

解决死锁最重要的事情,就是决定回滚死锁环中哪个事务,也就是选择哪个事务作为死锁受害事务。

选择死锁受害事务之前,还要做一件比较重要的小事,就是按照死锁环中各事务进入锁等待状态的时间从先到后进行排序。排序之后的事务,会存放到一个数组里,我们称之为死锁数组。

之所以要这么做,是为了根据其它条件无法选出哪个事务作为死锁受害事务的情况下,选择最晚进入锁等待状态的事务作为死锁受害事务。

给死锁环中各事务排序之后,就可以基于死锁数组来选择死锁受害事务了。

这个过程当然又要遍历死锁数组了,同样,每次取死锁数组中的一个事务。

第 1 轮循环有点特殊,直接把取到的事务(死锁数组中第一个事务)作为候选受害事务。

第 2 轮及以后的循环,把取到的事务和上一轮循环选出来的候选受害事务进行比较,决定两者之中谁作为本轮循环的受害事务。

选择谁作为本轮循环的受害事务,这是个艰难的决定,过程如下。

第 1 步,根据两个事务的优先级,决定谁是本轮循环的受害事务。

两个事务中,如果一个是高优先级事务(优先级大于 0),一个是低优先级事务(优先级等于 0),选择低优先级事务作为本轮循环的受害事务。

如果两个事务都是高优先级事务(优先级大于 0),选择优先级更低的事务作为本轮循环的受害事务。

如果两个事务都是低优先级事务(优先级等于 0),进入第 2 步。

第 2 步,根据事务是否改变(插入、更新、删除)了不支持事务的表(例如 MyISAM 表)的数据,决定谁是本轮循环的受害事务。

两个事务中,如果只有一个事务改变了不支持事务的表的数据,选择它作为本轮循环的受害事务。

如果两个事务都没有改变,或者都改变了不支持事务的表的数据,进入第 3 步。

第 3 步,根据事务的回滚成本,决定谁是本轮循环的受害事务。

事务的回滚成本,由两部分相加得到:

  • 事务进入锁等待状态之前,产生的 undo 日志数量。
  • 事务进入锁等待状态之前,加表锁和行锁总共创建了几个锁结构。

如果两个事务回滚成本不同,选择成本低的那个作为本轮循环的受害事务,否则进入第 4 步。

第 4 步,选择本轮循环取到的事务作为受害事务。

来到这一步,说明前三步都无法在两个事务中选出一个作为本轮循环的死锁受害事务。

这两个事务是:本轮循环取到的事务、上一轮循环选出来的受害事务。

因为死锁数组中各事务已经按照进入锁等待状态的时间先后排了序,这一步直接把本轮循环取到的事务作为本轮循环的受害事务,其实隐含了一个逻辑,就是选择两个事务中更晚进入锁等待状态的事务,作为本轮循环的受害事务。

遍历完死锁数组中所有事务之后,最终会选出一个事务作为受害事务。

2. 计算并更新事务权重

前面介绍过,在准备工作阶段,死锁线程提升阻塞事务权重时,死锁环中锁等待事务的权重,不会累加到阻塞事务的权重上,而是要等到确定死锁受害事务之后,再为死锁环中除受害之外的其它事务进行一次提升权重的操作。

现在,是时候了。

提升权重的过程,从被死锁受害事务阻塞的那个事务开始,根据死锁环中各事务的等待关系,逐个把锁等待事务的权重累加阻塞事务的权重上。

上面只介绍了提升权重操作,其实还有一个降低权重操作,就是把死锁受害事务的权重降为 0。

以上提升权重、降低权重操作的结果,都临时存放在权重数组里。

完成以上操作之后,死锁环中所有事务的权重都会更新到对应的事务对象中。

3. 记录死锁日志

如果系统变量 innodb_print_all_deadlocks 的值为 ON,死锁检查线程还会把死锁的详细信息写入 MySQL 的错误日志文件中。

示例 SQL 写入 MySQL 错误日志文件的死锁信息如下:

2024-07-07T13:00:15.602373Z 0 [Note] [MY-012468] [InnoDB] Transactions deadlock detected, dumping detailed information.
2024-07-07T13:00:15.602446Z 0 [Note] [MY-012469] [InnoDB]  *** (1) TRANSACTION:
TRANSACTION 227599, ACTIVE 21 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1192, 2 row lock(s)
MySQL thread id 8, OS thread handle 123145400471552, query id 96 localhost 127.0.0.1 root statistics
SELECT i1 FROM t1 WHERE id = 20 FOR UPDATE
2024-07-07T13:00:15.602597Z 0 [Note] [MY-012469] [InnoDB]  *** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 46 n bits 80 index PRIMARY of table `test`.`t1` trx id 227599 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 0000000a; asc     ;;
 1: len 6; hex 000000035958; asc     YX;;
 2: len 7; hex 82000000a50110; asc        ;;
 3: len 4; hex 80000065; asc    e;;

2024-07-07T13:00:15.603277Z 0 [Note] [MY-012469] [InnoDB]  *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 46 n bits 80 index PRIMARY of table `test`.`t1` trx id 227599 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 00000014; asc     ;;
 1: len 6; hex 000000035958; asc     YX;;
 2: len 7; hex 82000000a5011d; asc        ;;
 3: len 4; hex 800000c9; asc     ;;

2024-07-07T13:00:15.603950Z 0 [Note] [MY-012469] [InnoDB]  *** (2) TRANSACTION:
TRANSACTION 227600, ACTIVE 17 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1192, 2 row lock(s)
MySQL thread id 11, OS thread handle 123145401536512, query id 97 localhost 127.0.0.1 root statistics
SELECT * FROM t1 WHERE id = 10 FOR UPDATE
2024-07-07T13:00:15.604083Z 0 [Note] [MY-012469] [InnoDB]  *** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 46 n bits 80 index PRIMARY of table `test`.`t1` trx id 227600 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 00000014; asc     ;;
 1: len 6; hex 000000035958; asc     YX;;
 2: len 7; hex 82000000a5011d; asc        ;;
 3: len 4; hex 800000c9; asc     ;;

2024-07-07T13:00:15.604741Z 0 [Note] [MY-012469] [InnoDB]  *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 46 n bits 80 index PRIMARY of table `test`.`t1` trx id 227600 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 0000000a; asc     ;;
 1: len 6; hex 000000035958; asc     YX;;
 2: len 7; hex 82000000a50110; asc        ;;
 3: len 4; hex 80000065; asc    e;;

2024-07-07T13:00:15.605401Z 0 [Note] [MY-012469] [InnoDB] *** WE ROLL BACK TRANSACTION (2)

前面带日期和时间的日志,只有系统变量 log_error_verbosity 的值为 3,才会记录到 MySQL 错误日志文件中。

4. 唤醒死锁受害事务

死锁环中,选择出来的受害事务,会回滚。回滚操作并不是由死锁检查线程完成,而是由事务自己完成。

要想让受害事务自己回滚,它得知道自己被选择成为死锁受害事务了,这个操作由死锁检查线程完成。

死锁检查线程会给死锁受害事务打个标志,让它在被唤醒之后,知道自己被选择成为死锁受害事务了。

死锁受害事务进入锁等待状态之前,创建了一个锁结构,这个锁结构的 type_mode 属性的第 9 位被设置为 1 了,表示这个锁结构处于锁等待状态。

现在,这个锁结构需要从事务对象的 trx_locks 链表中删除。

如果这个锁结构对应的是行锁,还需要从 rec_hash 的数组中对应的行锁结构链表中删除。

如果这个锁结构对应的是表锁,还需要从表对象的 locks 链表中删除。

然后,死锁检查线程会触发死锁受害事务的等待事件,唤醒死锁受害事务。这个等待事件,保存在死锁受害事务占用的那个 slot 对应的 srv_slot_t 对象的 event 属性中。

到这里,死锁检查线程检查并解决死锁的过程就结束了。

剩下工作,就由死锁受害事务自己完成了。

死锁受害事务要完成什么工作?

当然是回滚了。

5. 总结

死锁检查线程解决死锁的过程如下:

  • 把死锁环中各事务按照进入锁等待状态的先后顺序排好序,放到死锁数组中。
  • 遍历死锁数组,每轮循环取一个事务。
  • 第 1 轮循环取死锁数组中第 1 个事务作为候选死锁受害事务。
  • 第 2 轮及以后的循环,根据事务的优先级、是否改变了不支持事务的表的数据、事务的回滚成本,从本轮循环取到的事务,和上一轮循环选出来的死锁受害事务两者中选择一个,作为本轮循环的受害事务。
  • 最后一轮循环选出来的受害事务,就是最终的死锁受害事务,这个事务会回滚。

选出死锁受害事务之后,死锁检查线程还会根据系统变量 innodb_print_all_deadlocks 的值,决定是否记录死锁日志。

然后,会给死锁受害事务打个标记,再唤醒死锁受害事务。

更多技术文章,请访问:https://opensource.actionsky.com/

关于 SQLE

SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。

✨ Github:https://github.com/actiontech/sqle

📚 文档:https://actiontech.github.io/sqle-docs/

💻 官网:https://opensource.actionsky.com/sqle/

👥 微信群:请添加小助手加入 ActionOpenSource

🔗 商业支持:https://www.actionsky.com/sqle

MySQL死锁产生的原因和解决方法 线程安全问题以及MySQL死锁产生的原因和解决方法排查方法和案例分析 阅读详情

相关推荐

MySQL死锁解析与解决方法

在数据库管理中,死锁是一种常见而又棘手的问题。当多个事务相互等待对方释放锁资源时,死锁就会发生。本文将介绍MySQL中死锁产生的原因、如何查询死锁,以及解决死锁的方法。

sg_knight的专栏 1639

【MySQL锁篇】MySQL死锁问题以及解决方案

mysql死锁及其解决办法

weixin_56738054的博客 1万+

怎么避免mysql死锁问题以及解决死锁

什么是死锁 问题现象(锁超时会回滚) InnoDB 锁类型 间隙锁( gap lock ) next-key lock (临键锁) 意向锁( Intention lock ) 插入意向锁( Insert Intention lock ) 锁模式兼容矩阵 阅读死锁日志 经典案例分析 案例一:事务并发 insert 唯一键冲突 案例一:先 update 再 insert 的并发死锁问题 如何尽可能避免死锁 解决方法 粗暴方式 文雅方式 对于锁的建议 如何定位死锁成因

1267

MySQL死锁了怎么办(死锁的产生及解决方案),死锁的案例,死锁的排查,死锁的解决,如何避免死锁的发生

死锁是指2+的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

weixin_44797327的博客 1万+

拆解特斯拉Optimus的关节技术:谐波减速器在仿人机器人中的5个精妙设计

本文深度解析特斯拉Optimus仿人机器人关节中的谐波减速器技术,揭示其五大工程突破:微型化材料革命、两万分之一圈精度实现、碳纤维柔轮轻量化、智能运维系统及国产替代方案。重点探讨谐波减速器如何通过创新设计和先进材料实现精准传动,为仿人机器人提供高效可靠的关节动力解决方案。

omega的博客 1075

别光看文档了!手把手带你用Habitat-Lab跑通第一个PointNav任务(附完整代码与避坑指南)

本文详细介绍了如何使用Habitat-Lab快速跑通第一个PointNav任务,包括环境配置、依赖安装、数据集下载与路径配置等关键步骤,并提供了完整的代码实现与常见问题排查指南。特别适合刚接触Habitat-Lab的开发者,帮助避开官方Quickstart未提及的坑,快速上手具身AI任务。

weixin_42662293的博客 272

怎么解决mysql死锁问题_mysql死锁问题的解决

常常在使用Navicat或者JDBC插入数据到mysql时,会遇见中文乱码问题,这时怎么解决问题呢? 请看下面的总结: 1、建表时没有指定统一的编码格式导致 错误的建表方式: CREATE TABLE database_user( ID varchar(40) , UserID varcha见官方文档:http://dev.mysql.com/...

weixin_29190169的博客 1276

映泰TB250-BTC主板魔改BIOS支持8/9代CPU实战与开机故障排查

BIOS(基本输入输出系统)是计算机硬件与操作系统之间的桥梁,负责初始化硬件和提供运行时服务。其工作原理是通过存储在主板芯片中的固件程序,在上电自检(POST)阶段完成对CPU、内存等关键组件的检测与配置。魔改BIOS的技术价值在于突破硬件限制,通过修改微码和电源管理模块,让旧平台支持新处理器,从而以极低成本实现性能跃升,在预算有限或追求极致性价比的DIY、办公和软路由等应用场景中极具吸引力。本文以映泰TB250-BTC矿板为例,详细解析了通过软刷方式刷入魔改BIOS,并重点解决了刷写后常见的“开机风扇转一

weixin_29164185的博客 406

Mysql死锁问题如何排查和解决

发生死锁了,如何排查和解决呢?本文将跟你一起探讨这个问题准备好数据环境模拟死锁案发分析死锁日志分析死锁结果在分析死锁日志前,先做一下锁介绍,哈哈~最后,遇到死锁问题,我们应该怎么分析呢?模拟死锁场景查看死锁日志找出死锁SQLSQL加锁分析,这个可以去官网看哈分析死锁日志(持有什么锁,等待什么锁)熟悉锁模式兼容矩阵,InnoDB存储引擎中锁的兼容性矩阵。

qq_43842093的博客 5509

突破Shopee平台数据采集的风控挑战与技术解决方案

高效、稳定、合规的数据采集能力,始终是我们服务的核心价值。多类型代理组合:采用高匿名住宅代理(模拟真实用户IP)与数据中心代理(高并发需求)混合策略,结合IP轮换频率与目标国家后缀(如.com.my、.vn)动态匹配14。反反爬数据过滤:针对Shopee页面中的混淆数据(如虚假价格标签、隐藏元素),采用XPath精准定位结合正则表达式清洗,确保数据准确性89。随机化请求间隔:在爬虫代码中引入随机延迟(如1-5秒),并模拟“浏览-点击-滚动”等用户行为链,降低行为模式的可预测性48。

klj3388的博客 2977

Python遥感技术实战:NDWI与MNDWI水体提取算法对比与优化

本文详细对比了NDWI与MNDWI两种水体提取算法在Python遥感技术中的应用。通过实战代码演示,分析了二者在自然与城镇场景下的表现差异,并重点介绍了阈值优化与后处理技巧,旨在帮助读者掌握高效、精准的水体提取方法,提升遥感数据分析能力。

f6g7h8i9j的博客 499

mysql 的一个死锁问题解决

这里说的是innodb类型的死锁! 网上找了好多东西 各种命令查看死锁信息,后面这条能用: show engine innodb status;(根据mysql版本而异) 这命令在mysql命令行执行后如果有死锁 会出现下面这一块: ------------------------ LATEST DETECTED DEADLOCK ------------------------

放纵的青春的专栏 1万+

【车载以太网】ATU(Address Translation Unit / Address Table Unit)

【车载以太网】ATU(Address Translation Unit / Address Table Unit)

天赐好车的博客 152

mysql:MySQL死锁问题全链路解决方案

预防层面统一资源访问顺序减小事务粒度缩短事务执行时间检测层面完善的监控告警系统定期分析死锁日志关键业务链路埋点恢复层面合理的重试机制优雅降级方案事务补偿机制架构层面热点数据分片读写分离引入消息队列削峰Plan -> 基线测量与问题识别Do -> 实施优化方案Check -> 监控效果指标Act -> 标准化成功经验通过以上多维度的解决方案,我们可以在保证系统高并发能力的同时,将死锁发生率控制在可接受范围内,实现系统稳定性和性能的最佳平衡。

weixin_43290370的博客 984

一文搞懂YOLO各版本差异:v5易用、v8多任务、v10低延迟,该怎么选?

YOLOv5的“易用”是为了降低入门门槛,适合新手启蒙和旧项目维护;YOLOv8的“多任务”是为了满足工业需求,成为目前的主流版本;YOLOv10的“低延迟”是为了适配边缘计算,代表未来的发展趋势。选型的核心不是“选最新的”,而是“选最适合自己场景的”。记住选型口诀,按场景对号入座,就能避开99%的坑。希望这篇文章能帮你彻底搞懂各版本差异,选对属于自己的YOLO版本!

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1169

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

mysql并发死锁问题解决

一般根据多条件过滤后更新update在高并发的时候会导致死锁,进而事务失败。 这是因为mysql行级锁并不是直接锁记录,而是锁索引,如果一条SQL语句用到了主键索引,mysql会锁住主键索引;如果一条语句操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引。 参考: https://blog.youkuaiyun.com/guanfengliang1988/article/details/80356648 https://blog.youkuaiyun.com/usst_lidawe...

shy_snow的专栏 1101

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

mysql死锁问题如何解决

在MySQL数据库中,当两个或多个事务互相等待对方释放锁资源而陷入僵局状态时,就会发生死锁。优化查询:尽可能减少事务持有锁的时间,避免长时间占用锁资源,合理设计索引以减少锁冲突。调整事务隔离级别:根据具体业务需求调整事务隔离级别,如降低隔离级别,避免不必要的锁等。参数,开启后可以自动检测到死锁并将死锁信息记录在错误日志中,从而进行分析和处理。重试机制:一旦检测到死锁,可以让事务回滚并重试,通常情况下死锁只会是暂时性的。分解大事务:将大事务拆分成较小的子事务,减少事务内操作的资源占用和锁竞争。

weixin_43106895的博客 794

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

MySQL死锁问题定位与解决方案

mysql死锁问题

qq_46301912的博客 1300

如何解决MySQL死锁问题

MySQL在并发环境下可能会出现死锁问题。死锁是指两个或多个事务互相等待对方释放资源,导致无法继续执行的情况。需要根据具体情况分析和实施相应的解决方案,并进行测试和验证,以确保解决死锁问题,并提高数据库的并发性能。

越努力越幸运。 1043

mysql死锁问题实际场景排查与对应方法解决

在数据库操作中,死锁是一个常见的问题,尤其是在高并发的场景下。死锁会导致事务无法继续执行,影响系统性能和用户体验。

m0_73953178的博客 1832

MySQL 死锁问题排查与解决

在数据库应用中,死锁是一个常见的问题。本文将以 MySQL 为例,介绍死锁问题的排查方法和解决措施。

m0_57836225的博客 812

如何解决服务器中 MySQL 的死锁问题

如何解决服务器中 MySQL 的死锁问题

2409_89014517的博客 1362

【MySQL】之死锁问题及其解决方案

数据库死锁问题是我们老生常谈的问题了,在我们实际开发过程中经常会遇到,为了尽量避免出现死锁,我们需要了解出现死锁的场景。同时,如果线上出现了死锁之后怎么去分析、排查和解决,下面我就这两点介绍一下。

王廷云的博客 2596

Mysql 之 死锁问题如何排查和解决

mysql死锁

enjoy.day 477

MySQL 死锁问题分析与解决方案

解决 MySQL 死锁需结合。

weixin_45226922的博客 1844
上一篇: MySQL 备库可以设置 sync_binlog 非 1 吗?
下一篇: MySQL5.7 中连续 Crash 引发 GTID 丢失
爱可生开源社区
博客等级 码龄8年 1936粉丝 1004原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值