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

时间:2022-06-03 06:53:05

问题描述: 

检查程序运行日志的时候, 发现了很多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)
冲突 冲突 兼容 兼容