![高性能MySQL(第4版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/591/47548591/b_47548591.jpg)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人
死锁
死锁是指两个或多个事务相互持有和请求相同资源上的锁,产生了循环依赖。当多个事务试图以不同的顺序锁定资源时会导致死锁。当多个事务锁定相同的资源时,也可能会发生死锁。例如,设想运行下面两个针对主键为(stock_id,date)的StockPrice表的事务:
事务1
![](https://epubservercos.yuewen.com/3CB62F/26947440007593006/epubprivate/OEBPS/Images/44257_40_1.jpg?sign=1738896258-xMo7hLETDsC7xzSXZxNdFaMQ2gxzSA5C-0-baca1217be88faca14d0225008cc87e7)
事务2
![](https://epubservercos.yuewen.com/3CB62F/26947440007593006/epubprivate/OEBPS/Images/44257_40_2.jpg?sign=1738896258-9rkFLf9EQU7fYVI4ofFHs4bS7oQZMgsS-0-9e1f4432a441fef5946a23b7071671e6)
每个事务都开始执行第一个查询,在处理过程中会更新一行数据,同时在主键索引和其他唯一索引中将该行锁定。然后,每个事务将在第二个查询中尝试更新第二行数据,却发现该行已经被锁定。这两个事务将永远等待对方完成,除非有其他因素介入解除死锁。我们将在第7章进一步介绍索引如何随着模式的发展而影响或破坏查询的性能。
为了解决这个问题,数据库系统实现了各种死锁检测和锁超时机制。更复杂的系统,比如InnoDB存储引擎,检测到循环依赖后会立即返回一个错误信息。这可能是一件好事——否则,死锁将表现为非常缓慢的查询。还有一种方式,当超过锁等待超时的时间限制后直接终止查询,这样做通常来说不太好。InnoDB目前处理死锁的方式是将持有最少行级排他锁的事务回滚(这是一种最容易回滚的近似算法)。
锁的行为和顺序是和存储引擎相关的。同样的一系列查询语句,有些存储引擎会产生死锁,有些则不会。死锁的产生有双重原因:有些是因为真正的数据冲突,这种情况通常很难避免,但有些则完全是由于存储引擎的实现方式导致的。[8]
一旦发生死锁,如果不回滚其中一个事务(部分或全部),就无法打破死锁。对于事务型的系统,这是无法避免的,所以应用程序在设计时必须考虑如何处理死锁。大多数情况下只需要重新从头开始执行被回滚的事务即可,除非又遇到另一个死锁。