前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL 使用 for update 引发死锁原因分析

MySQL 使用 for update 引发死锁原因分析

原创
作者头像
_春华秋实
发布2023-10-15 16:56:47
5200
发布2023-10-15 16:56:47
举报
文章被收录于专栏:_春华秋实_春华秋实

在之前的一次开发需求中使用了 for update 实现悲观锁,最后导致出现了很多的 MySQL 死锁报警,现记录下死锁产生的原因。

为什么使用 for update

业务中需要维护数据状态(例如进行中、失败、成功),但是这个状态是通过多条子任务最终的结果决定的,场景如下

  • 如果记录结果有一个失败的,这个任务就是失败的
  • 如果记录都成功了,这个任务最终就是成功状态

根据上面场景可以想到,更新数据分为两个步骤

  1. 查询子任务最终的状态
  2. 修改任务的状态

为了保证数据在并发情况下的正确性,当时想到的是保证查询和修改是一个原子性操作,所以决定在查询时使用 for update 对查询到的数据加锁。根据查询的结果修改任务的状态。但是后来发现这个修改逻辑造成 MySQL 死锁。

死锁原因分析

造成死锁的原因主要和 for update 对数据加锁的过程有些关系,加锁过程描述:

MySQL innodb 存储引擎默认的隔离级别时 RR 级别,而RR隔离级别,默认是使用Next-key Lock,Next-Key Lock加锁有下面几个规则。

  1. Next-Key Lock是前开后闭区间。
  2. 查找过程中访问到的对象才会加锁。
  3. 索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为 record lock。
  4. 索引上的等值查询,向右遍历时且最后一个值不满足等值条件时,next-key lock 退化为 gap lock。

具体案例分析

表结构

代码语言:javascript
复制
mysql> show create table user;

CREATE TABLE `user` (

  `id` int NOT NULL,

  `score` int DEFAULT NULL,

  KEY `socre` (`score`) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci |

1 row in set (0.00 sec)

当前表结构,只有一个普通索引score。我们下面的测试都是在普通索引score的基础上完成的。

插入数据

复现案例

分析上图的两个事务的操作,在A事务加锁之后,实际的加锁范围是[10,30),sql查询流程如下:

  1. 通过score索引,找到第一个值,score=10,不满足条件,继续向下寻找。
  2. 找下一个节点score=20,符合条件,会加上行锁和间隙锁。此时的加锁状态是(10,20];但是根据规则2,查找过程访问到的上一个记录score=10,所以会将10也锁住,加锁范围变成[10,20]。
  3. score不是唯一索引,所以会继续向下寻找,下一个节点为30,满足规则2,所以会加上(20,30],但是30不满足等值查询score=20,所以根据第4条规则next-key lock退化为gap lock(20,30)。
  4. 至此,事务加锁结束,最终的加锁范围是[10,30)

间隙锁细节总结

  • 间隙锁锁定的是索引记录之前和之后的一个间隙范围。
  • 可以对同一个间隙重复加间隙锁。
  • 间隙锁可能造成死锁。
  • 间隙锁是RR隔离级别下的。
  • 间隙锁只影响一般索引,对于唯一索引或者主键,如果查询的结果包含这个记录,那么另外的会话插入该记录前后,不会产生间隙锁;如果查询结果不包含这个记录,另外的会话插入该记录前后的间隙,会产生间隙锁。

经过上面的流程可以知道 for update 不仅会锁住查询到的数据, 也会锁住不满足查询条件的数据,当查询不到数据的时候甚至可能演变成表锁,因为不同事务的间隙锁可以重复加锁,所以当两个事务同时锁住某些相同的数据,并对这部分数据进行修改时就会出现死锁的情况

参考文章

MySQL 锁类型总结

MySQL 间隙锁,锁过程详解

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么使用 for update
  • 死锁原因分析
  • 具体案例分析
  • 间隙锁细节总结
  • 参考文章
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档