mysql5.7 为什么刚要死锁立刻就会报错而无需等待超时?

问题起因

自己做了个人造死锁的小实验:

Session1

Session2

Begin;

 

Select * from t where id=1 lock in share mode;

 

 

Begin;

 

Select * from t where id=1 lock in share mode;

 

Delete from t where id=1;//waiting

Delete from t where id=1;

//立刻报错:Deadlock found when trying to get lock; try restarting transaction

 

 

按我对mysql的理解,死锁出现之后应该慢慢等他超时然后回滚,结果这里刚敲了执行立刻错就报出来了,显然不是用的超时;那我盲猜mysql会保存每个session持有的资源,每次运行新的sql语句会把所有session以持有的资源扫描一遍看看有没有可能造成死锁。但是emmm,这个策略感觉效率会很低。

于是很好奇mysql用了什么检测机制。

答案结论

5.7版本开始,innodb_deadlock_detect开关变量被引入且默认开启。(可以用show variables like '%innodb_deadlock_detect%';查看)

于是mysql有了两种途径检测死锁:原来的等待超时和新增的死锁检测。

死锁检测的原理是构建一个以事务为顶点、锁为边的有向图,判断有向图是否存在环,存在即有死锁,所以如果同时存在大量事务,那么检测或许会非常非常慢。因此mysql对此进行了上限控制。如果运行的时候报错

TOO DEEP OR LONG SEARCH IN THE LOCK TABLE WAITS-FOR GRAPH, WE WILL ROLL BACK FOLLOWING TRANSACTION

那就表示目前正在等待的事务数量已达到200上限。超过200个事务的等待列表被视为死锁,并且尝试检查等待列表的事务被回滚。如果锁定线程必须查看等待列表中事务拥有的超过1,000,000个锁,也可能发生相同的错误。(详见MySQL5.7文档

顺便,无需担心死锁检测机制的代码会发生死锁,因为它无需等待资源,并不具备死锁发生的条件

搜寻答案过程中找到的其他有趣point

innodb执行事务的完全回滚时,事务设置的所有锁都会被释放。但是,如果错误导致仅回滚一条sql语句,则该语句设置的一些锁可能会被保留。发生这种情况是因为innodb以这样一种格式存储行锁:它在以后无法知道哪个锁是由哪个语句设置的。

  1.  

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值