当前位置: 首页 > news >正文

遇到 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 源码。 爱可生开源社区出品,原创内容未经授权不得随意使用&#xff0…...

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文件,帮助大学选题。赠送开题报告模板&#xff…...

从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部署环境 表是索引数据是放在磁盘上的&#xf…...

更小、更安全、更透明: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、多群体覆盖,定制个性化方案 如意助听器针对不同听损程度的听障患者设计了不同款式助听器,贴…...

生物实验室设备文件采集如何才能质量和效率双管齐下?

生物实验室的设备文件采集是实验室运营、科研活动和数据科学实践应用中不可或缺的一环。通过数据采集,实验室可以优化资源配置、提高实验结果的准确性和可靠性、支持科研水平的提升,并确保数据的安全性和可追溯性。因此,实验室应高度重视设备…...

Framework源码整编、单编、烧录过程

目录 一.背景 二.整编方式 二.单编方式 三.烧录 一.背景 源码编译分为整编和单编,整编通常耗时较长,单编则速度很多,如果我们进行一个小的修改想要立马验证的话单编就很合适 二.整编方式 开始执行编译操作,总共三步. 执行source操作source build/envsetup.sh .执行lunc…...

TypeScript类型断言

TypeScript类型断言是TypeScript中一个强大且有用的特性,它允许开发者在编译时明确指定一个值的类型,即使TypeScript无法自动推断出这个类型。类型断言类似于其他编程语言中的类型转换,但它不会改变变量的运行时值,而只是告诉编译…...

Mallet:一款针对任意协议的安全拦截代理工具

关于Mallet Mallet是一款功能强大的协议安全分析工具,该工具支持针对任意协议创建用于安全审计的拦截代理,该工具本质上与我们所熟悉的拦截Web代理类似,只是通用性更强。 工具运行机制 Mallet建立在Netty框架之上,并且依赖于Net…...

【IEEE出版】第五届大数据、人工智能与软件工程国际研讨会(ICBASE 2024,9月20-22)

第五届大数据、人工智能与软件工程国际研讨会(ICBASE 2024)将于2024年09月20-22日在中国温州隆重举行。 会议主要围绕大数据、人工智能与软件工程等研究领域展开讨论。会议旨在为从事大数据、人工智能与软件工程研究的专家学者、工程技术人员、技术研发人…...

自修室预约小程序的设计

管理员账户功能包括:系统首页,个人中心,学生管理,公告通知管理,自修室管理,座位预约管理,预约取消管理,管理员管理,系统管理 微信端账号功能包括:系统首页&a…...

用于跟踪个人图书馆的BookLogr

什么是 BookLogr ? BookLogr 是一款网络应用,旨在帮助您轻松管理个人图书馆。这项自托管服务可确保您完全控制数据,提供安全且私密的方式来跟踪您拥有、阅读或希望阅读的所有书籍。您也可以选择向公众自豪地展示您的图书馆,与您的…...

深入解析JVM垃圾回收机制:Full GC、Minor GC与Major GC

目录 引言垃圾回收的基本概念 什么是垃圾回收GC的分类JVM内存模型 堆内存非堆内存Minor GC 触发条件运行机制对性能的影响...

Windows10点击文件夹右键卡死的解决办法

1、首先同时按下【WinR】打开运行页面,输入命令【regedit】按下回车或者点击确定。 2、打开注册表编辑器后,定位到如下位置“HKEY_CLASSES_ROOT\Directory\Background\Shellex\ContextMenuHandlers”。 3、然后在其中将所有名为“New”的文件或项全部删…...

C# 设计模式之单例模式

总目录 前言 本文是个人基于C#学习设计模式总结的学习笔记,希望对你有用! 1 基本介绍 定义:确保一个类只有一个实例,并提供一个全局访问点。 本质就是保证在整个应用程序的生命周期中,任何一个时刻,单例…...

【组合数学】【Python】【小练习】一、斯特灵近似式求阶乘

一、问题介绍 斯特灵(Stirling)近似式,是数学分析中,用于求阶乘近似值的一个常用公式,其简单的表述形式为: 二、Python实现 使用Python,循环从n1至n98,分别输出n的阶乘值、斯特灵公…...