MySQL 间隙锁导致的死锁场景分析
实际业务场景
在我们使用mysql的时候,如果不注意间隙锁容易引起死锁,最近分析一个业务场景就是间隙锁导致的死锁,业务抽象如下:
系统有一个批量新增业务资源的功能,实现逻辑如下(businnessid为非唯一索引):
update 业务表 set isdeleted=1 where bussinessid=123;
insert into 业务表
在并发场景下,以上逻辑产生了死锁。
以下为死锁具体分析以及还原死锁产生过程,最后给出解决方案。
创建一张表
CREATE TABLE `lock_demo` (
`id` INT NOT NULL AUTO_INCREMENT,
`index` INT NOT NULL,
`name` VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `index` (`index`)
)
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
;
死锁演示
事务一 |
事务二 |
update lock_demo set name='a' where index=1; |
|
|
update lock_demo set name='a' where index=2; 未卡住,间隙锁之间不冲突 |
insert into lock_demo(id,`index`,name)values(1,1,'1'); 卡住,被事务二的间隙锁锁住 |
|
|
insert into lock_demo(id,`index`,name)values(2,2,'2'); 检测到死锁 |
具体步骤
步骤一
事务一
先更新一条记录(不存在),不提交。
步骤二
事务二
更新一条记录(不存在),不提交。
步骤三
事务一,执行一条新增语句,被事务二的间隙锁锁住
步骤四
事务二,执行一条新增语句,被事务一的间隙锁锁住,系统检测到死锁
解决方案
对于以上的业务,可以改写sql避免死锁
select id from 业务表 where bussinessid=123;
如果存在,
update 业务表 set isdeleted=1 where id in (xxx);
insert into 业务表
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了