最近生产出现一次死锁问题,很棘手,望各位大佬相助分析一下死锁产生原因
注:
ID主键自增
Status普通索引,可取值1初始,2过程中,3成功,4失败,5过期
Priority普通索引,目前取值均为1
UniqueNumber唯一索引,32位md5值
1.InnoDB默认RR可重复读级别
2.两实例四个相同线程,线程执行顺序如下
①
select
Content,Priority,UniqueNumber
from t
where (Status = 1 or Status = 4)
order by Priority
asc limit 0,100
for update
②
update t set Status = 2
where UniqueNumber = '32位md5'
③
若过期update Status = 5
若失败update Status = 4
若成功update Status = 3其中①②在同一事务中,因为①②所在同一方法加了@transaction注解
①②多线程串行,后面是多线程并行查看mysql死锁日志发现
①和②居然发生死锁,如图,实在想不明白
考虑了间隙锁等原因,但在实际环境无法复现
求各位大佬帮忙复现一下,万分感谢
注:
ID主键自增
Status普通索引,可取值1初始,2过程中,3成功,4失败,5过期
Priority普通索引,目前取值均为1
UniqueNumber唯一索引,32位md5值
1.InnoDB默认RR可重复读级别
2.两实例四个相同线程,线程执行顺序如下
①
select
Content,Priority,UniqueNumber
from t
where (Status = 1 or Status = 4)
order by Priority
asc limit 0,100
for update
②
update t set Status = 2
where UniqueNumber = '32位md5'
③
若过期update Status = 5
若失败update Status = 4
若成功update Status = 3其中①②在同一事务中,因为①②所在同一方法加了@transaction注解
①②多线程串行,后面是多线程并行查看mysql死锁日志发现
①和②居然发生死锁,如图,实在想不明白
考虑了间隙锁等原因,但在实际环境无法复现
求各位大佬帮忙复现一下,万分感谢
If you use FOR UPDATE with a storage engine that uses page or row locks, rows examined by the query are write-locked until the end of the current transaction.
语句②,你想把UniqueNumber = '32位md5'的行的status列设为2。
因为存在UniqueNumber = '32位md5'且status=1or4的行已经被语句①上了写锁,所以语句②想要修改status时会死锁。我猜你的误区可能是,认为语句①select Content,Priority,UniqueNumber 没有选status啊,为什么就被锁了呢。
这是因为Innoob支持行锁,是把整行全部锁掉,不可以只锁某一行的某几列。
您可以看一下我的blink,,因为分不够所以发不了帖子了。里面有一张死锁日志图片,①语句想获取next-key锁 ②语句想获取插入意向锁。实在搞不明白多线程情况下会发生这种情况。十分感谢!