遇到 MySQL 死锁问题如何解决?
终于来到死锁检查线程的第三步,可以解决死锁了。
作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 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 00: 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 00: 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 00: 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 00: 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 和 OceanBase 源码。 爱可生开源社区出品,原创内容未经授权不得随意使用࿰…...
Pyinstaller打包OSError: could not get source code【终极解决】
pyinstaller 打包的时候,发现只要是torch.jit.script装饰的函数,会报以下错误: Traceback (most recent call last):File "torch/_sources.py", line 25, in get_source_lines_and_fileFile "inspect.py", line 1123, i…...
【计算机毕业设计】707高校宿舍管理系统
🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板ÿ…...
从C++看C#托管内存与非托管内存
进程的内存 一个exe文件,在没有运行时,其磁盘存储空间格式为函数代码段全局变量段。加载为内存后,其进程内存模式增加为函数代码段全局变量段函数调用栈堆区。我们重点讨论堆区。 托管堆与非托管堆 C# int a10这种代码申请的内存空间位于函…...
Linux进程间通信--IPC之无名管道
进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。 IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams支持不同主机上的两个进程的IPC。...
Oracle19c数据库system密码锁定
一、在oracle 19c数据库中,cdb中system用户被锁定,locked 二、所在的pdb中的system用户状态是正常的,但不可用,连接的时候提示账号已锁定 三、解决 在cdb中将system用户解锁。 alter user system account unlock;...
java之hashCode() 方法和 equals(Object obj) 方法之间的关系
1、 hashCode() 方法和 equals(Object obj) 在Java中,hashCode() 方法和 equals(Object obj) 方法之间的关系是紧密相连的,特别是在使用基于哈希的集合(如 HashSet、HashMap、HashTable 等)时。这两个方法共同决定了对象在哈希表…...
首届「中国可观测日」圆满落幕
首届中国可观测日(Observability Day)在上海圆满落幕,为监控观测领域带来了一场技术盛宴。作为技术交流的重要平台,此次活动不仅促进了观测云与亚马逊云科技之间的深化合作,更标志着双方共同推动行业发展的重要里程碑。…...
[Docker][Docker NetWork][下]详细讲解
目录 1.网络管理命令1.docker network creatre2.docker network inspect3.docker network connect4.docker network disconnect5.docker network prune6.docker network rm7.docker network ls 2.docker bridge 详解0.基本概念1.默认 bridge2.自定义 bridge3.DNS解析4.端口暴露…...
安卓系统在未来如何更好地解决隐私保护与数据安全的问题?
安卓系统可以通过以下方式更好地解决隐私保护与数据安全的问题: 强化权限控制:安卓系统可以进一步加强对应用程序权限的管理,确保用户能够清楚地知道应用程序需要哪些权限,并给予用户更多的控制权,例如允许用户选择性地…...
MySQL innodb单表上限一般多少
参考:https://www.zhihu.com/question/351797203/answer/3137174084 1.MySQL innodb单表上限为啥都说是2k万条 2.GaussDB for MySQL 为啥可以突破单表2k万的限制 要讨论这两个问题,得先明确性下实际的DB部署环境 表是索引数据是放在磁盘上的…...
更小、更安全、更透明:Google发布的Gemma推动负责任AI的进步
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
基于Django框架的医疗耗材管理系统的设计实现-计算机毕设定制-附项目源码(可白嫖)48999
摘 要 在目前的形势下,科技力量已成为我国的主要竞争力。而在科学技术领域,计算机的使用逐渐达到成熟,无论是从国家到企业再到家庭,计算机都发挥着其不可替代的作用,可以说计算机的可用领域遍及生活、工作的各个方面。…...
物联网协议篇(1):modbus tcp和modbusRTU的区别是什么?
Modbus TCP和Modbus RTU是Modbus协议中的两种主要变体,它们在多个方面存在显著的区别。以下是它们之间的主要区别: 1. 物理层和数据传输方式 Modbus TCP (TCP/IP): 使用以太网作为物理层,通过TCP/IP协议进行通信。数据以数据包的形式在TCP连接上传输,具有较高的通信速度和…...
JVM系列 | 对象的消亡——HotSpot的设计细节
HotSpot 的细节实现 文章目录 HotSpot 的细节实现OopMap 与 根节点枚举根节点类型及说明HotSpot中的实现 OopMap 与 安全点安全点介绍如何保证程序在安全点上? 安全区域记忆集与卡表记忆集卡表 写屏障并发的可达性分析(与用户线程)并发可达性…...
vue 运行或打包过程报错 JavaScript heap out of memory(内存溢出)
安装 increase-memory-limit npm install increase-memory-limit 运行increase-memory-limit ./node_modules/.bin/increase-memory-limit 运行后会报以下错误: "node --max-old-space-size10240" 不是内部或外部命令,也不是可运行的程序…...
git分支提交方法
先下载最新代码 改动文件覆盖 cp 文件到~/file/ git add添加文件 git commit提交本地 建立分支 git diff .c git status -uno git add git commit git checkout -b issue-lyd git push origin issue-lyd...
从微架构到向量化--CPU性能优化指北
引入 定位程序性能问题,相信大家都有很多很好的办法,比如用top/uptime观察负载和CPU使用率,用dstat/iostat观察io情况,ptrace/meminfo/vmstat观察内存、上下文切换和软硬中断等等,但是如果具体到CPU问题,我…...
声声入耳,事事如意 爱可声「如意」助听器即将上市!
如意助听器 Charm 爱可声全新系列「如意」助听器即将上市! 此次新品充分考虑了不同听损以及年龄的用户需求, 融合三大强劲性能。 1、多群体覆盖,定制个性化方案 如意助听器针对不同听损程度的听障患者设计了不同款式助听器,贴…...
生物实验室设备文件采集如何才能质量和效率双管齐下?
生物实验室的设备文件采集是实验室运营、科研活动和数据科学实践应用中不可或缺的一环。通过数据采集,实验室可以优化资源配置、提高实验结果的准确性和可靠性、支持科研水平的提升,并确保数据的安全性和可追溯性。因此,实验室应高度重视设备…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
