MySQL 因 select for update 导致的死锁问题 原因及解决方案

本文分析了使用悲观锁时MySQL中出现死锁的原因,并提供了一种解决方案,通过调整SQL语句顺序来避免死锁的发生。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述: 

检查程序运行日志的时候, 发现了很多DB死锁, 我这边程序中使用的是悲观锁, 因为考虑到不想让调用端重试。

死锁原因:

有多个请求同时希望insert表, 程序中逻辑如下:

select for update where uid = ?

if [obj ]not exist

insert 

else

update

死锁原因就是 select for update 如果记录不存在mysql会先加一个意向锁, 当多个请求(多个线程) 同时加了意向锁之后(意向锁之间可兼容), 第一个线程尝试insert的时候会尝试加排他锁, 这时排他锁会被第二个线程的pending住, 此时第二个线程尝试插入的时候, 也会尝试加排他锁, 这个时候就会出现deadlock的情况

 

解决方案如下:

select

if [obj] not exist

insert

else

select for update

update

 

现在用jmeter3个线程测试1次, 第一个可以成功, 后面两个mysql会抛出unique key异常, 我们在上层捕获异常,回滚并打印日志, 向调用方透明.


MYSQL中锁相互影响矩阵:

  共享锁
(S)
排他锁
(X)
意向共享锁
(IS)
意向排他锁
(IX)
共享锁(S) 兼容 冲突 兼容 冲突
排他锁(X) 冲突 冲突 冲突 冲突
意向共享锁
(IS)
兼容 冲突 兼容 兼容
意向排他锁
(IX)
冲突 冲突 兼容 兼容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值