一个MySQL死锁问题的反思

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 很早之前我写过几篇关于MySQL死锁的分析,比如 但是感觉不过瘾,而且分析的都是一些特定的场景,好像还缺少一些举一反三的感觉,所以今天就补上这一波。 MySQL里的锁兼容列表大体是这样的关系,如果第一次看会有些晕,感觉抓不住重点,其实有一点小技巧。

很早之前我写过几篇关于MySQL死锁的分析,比如

但是感觉不过瘾,而且分析的都是一些特定的场景,好像还缺少一些举一反三的感觉,所以今天就补上这一波。

MySQL里的锁兼容列表大体是这样的关系,如果第一次看会有些晕,感觉抓不住重点,其实有一点小技巧。

首先InnoDB实现了两种类似的行锁,即S(共享锁)和X(排他锁),而InnoDB层面的表级意向锁有IS(意向共享锁)和IX9意向排他锁),意向锁之间是互相兼容的,这句话很重要,按照这个思路里面一半的内容就明确了。而另外一部分则是S和X的兼容性。带着S锁和X锁的组合都是互相排斥,只有一类场景例外,那就是都是S锁,是兼容的。所以这个图按照这个思路几乎不用记就能基本理解了。

img_55d2af65d33df5d38c2515d71f80df38.jpe

看起来S锁的组合是很柔和的,从这种场景来看保持兼容,那么出死锁的概率应该很低吧,其实在RR,RC隔离级别下我们可以逐步扩展然后举一反三。

如果S锁的组合在两个会话中是互相兼容,那么接下来的X锁的组合就是互相排斥的。

img_93e6d1c02bb4bd32eef977b11e17516d.png

那么在两个会话并发的场景下,死锁的步骤如下:

mysql> create table dt1 (id int unique

Query OK, 0 rows affected (0.03 sec)

会话1:

begin;

select *from dt1 lock in share mode; --显式共享锁

会话2:

begin;

select *from dt1 lock in share mode; --显式共享锁

会话1:

insert into dt1 values(1); --阻塞

会话2:

insert into dt1 values(2); --触发死锁

所以上面的语句特点很明显,插入的数据分别是1和2,看起来互补冲突也不行。

我们进度稍快一些,我们可能很少看到直接声明share mode的方式,但是有很多时候由其他的场景会触发,其中的一个主要原因就在于对于duplicate数据的检查会开启S锁。这是比较特别的一点,需要注意。

按照这一点来扩展,很容易就可以扩展到3个会话中。

会话1只是负责插入一条数据,会话2,3也紧接着插入一条记录(会话2,3自动提交),但是因为唯一性索引的检查,会导致会话2和会话3都开启了S锁,因为兼容,所以暂时还没影响。如果会话1正常提交,会话2,3的检查会生效,导致数据插入不了,违反唯一性约束,但是我们反其道而行,就可以用一个rollback来释放锁,紧接着会话2和会话3都会获得S锁成功,紧接着获得X锁,细节算法就不说了。这个时候互相阻塞,导致会话3产生死锁,会话2的数据插入依然会成功。

会话1:

begin;

insert into dt1 values(1);

会话2:

insert into dt1 values(1);

会话3:

insert into dt1 values(1);

会话1:

rollback;

看起来很精巧的小测试,但是里面蕴含这大道理,比如按照这个思路,如果后面的两个语句都是delete,也会触发死锁。有的时候我们可以正面来图例,或者通过死锁日志来推理。给我的一个启发是太极。

img_cc5efabb956b190ec6c39e39f03f7a9c.jpe

放在锁的角度来理解就会好很多。

用一张不太形象的图表示就是,左边的部分是insert操作在会话1中,右边的是在会话2和会话3中,都持有S锁,然后会因为同样的原因事务回滚后,他们的S锁会升级为X锁导致死锁发生。

img_a28980e85f74ab3ca1506be7d94d24a5.png

按照这个思路,我们可以继续扩展出几个场景。比如delete的方式。

img_bbccc310aac06145a9b681019fb5ff0a.png

按照这样的思路,可以构建出很多的死锁场景来。
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
SQL 关系型数据库 MySQL
MySQL死锁及源码分析!
MySQL死锁及源码分析!
MySQL死锁及源码分析!
|
1月前
|
SQL 关系型数据库 MySQL
案例剖析:MySQL唯一索引并发插入导致死锁!
案例剖析:MySQL唯一索引并发插入导致死锁!
案例剖析:MySQL唯一索引并发插入导致死锁!
|
1月前
|
SQL 关系型数据库 MySQL
案例剖析,MySQL共享锁引发的死锁问题!
案例剖析,MySQL共享锁引发的死锁问题!
|
3月前
|
SQL 关系型数据库 MySQL
遇到mysql数据库死锁,你会怎么排查?
遇到mysql数据库死锁,你会怎么排查?
248 0
|
12天前
|
SQL 算法 关系型数据库
面试:什么是死锁,如何避免或解决死锁;MySQL中的死锁现象,MySQL死锁如何解决
面试:什么是死锁,死锁产生的四个必要条件,如何避免或解决死锁;数据库锁,锁分类,控制事务;MySQL中的死锁现象,MySQL死锁如何解决
|
22天前
|
关系型数据库 MySQL 数据库
一个 MySQL 数据库死锁的案例和解决方案
本文介绍了一个 MySQL 数据库死锁的案例和解决方案。
36 3
|
2月前
|
监控 关系型数据库 MySQL
MySQL锁机制与解决死锁问题
MySQL锁机制与解决死锁问题
270 5
|
1月前
|
监控 关系型数据库 MySQL
一次彻底讲清如何处理mysql 的死锁问题
【10月更文挑战第16天】本文详细介绍了如何处理 MySQL 中的死锁问题,涵盖死锁的概念、原因、检测方法及解决策略,强调通过优化事务设计、调整数据库参数、手动处理和预防措施等手段,有效减少死锁,提升数据库性能与稳定性。
219 0
|
3月前
|
存储 SQL 关系型数据库
深入MySQL锁机制:原理、死锁解决及Java防范技巧
深入MySQL锁机制:原理、死锁解决及Java防范技巧
|
3月前
|
SQL JavaScript 关系型数据库
Mysql索引不当引发死锁问题
本文通过真实案例解析了MySQL在高并发环境下出现死锁的问题。数据库表`t_award`包含多个索引,但在执行特定SQL语句时遭遇索引失效,导致更新操作变慢并引发死锁。分析发现,联合索引`(pool_id, identifier, status, is_redeemed)`因`identifier`允许为空值而导致索引部分失效。此外,`pool_id`上的普通索引产生的间隙锁在高并发下加剧了死锁风险。为解决此问题,文中提出了调整索引顺序至`(pool_id, status, is_redeemed, identifier)`等方案来优化索引使用,进而减轻死锁现象。