最近生产出现一次死锁问题,很棘手,望各位大佬相助分析一下死锁产生原因
注:
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死锁日志发现
①和②居然发生死锁,如图,实在想不明白
考虑了间隙锁等原因,但在实际环境无法复现
求各位大佬帮忙复现一下,万分感谢

解决方案 »

  1.   

    语句①,你给status=1或4的前100行加上了写锁,而且这个锁在事务结束后才会解开。
    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支持行锁,是把整行全部锁掉,不可以只锁某一行的某几列。
      

  2.   

    大佬你好,这种情况我尝试过,这种情况mysql并没有产生死锁,是等待超时了,我知道InooDB默认行级锁
    您可以看一下我的blink,,因为分不够所以发不了帖子了。里面有一张死锁日志图片,①语句想获取next-key锁 ②语句想获取插入意向锁。实在搞不明白多线程情况下会发生这种情况。十分感谢!