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