死锁
本文聊一聊事务中的死锁现象。死锁的定义是什么?死锁是指两个或者多个事务在同一个资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定相同的资源时,就很容易产生死锁。或者是多个事务同时锁定某一个相同的资源时,也非常容易产生死锁哦!
StockPrice表实例分析
假设现在有两个事务同时针对StockPrice
表进行相关的操作,如下:
事务一:
1 | START TRANSACTION; |
事务二:
1 | START TRANSACTION; |
这两个事务同时执行会发生什么呢?我们可以看到哈,事务一和事务二都执行完第一条SQL语句时,事务一因为操作了stock_id
为4且date
为2015-05-01的记录,因此锁定了第一条记录;同时事务二因为操作了stock_id
为3且date
为2015-05-02的记录,因此锁定了第二条记录;那么它们在执行第二句的时候,大家都是获取不到这个资源的,因为这个资源分别被两个事务占用了,这就形成了一个典型的死锁。解决的办法很简单,回滚其中的一个事务即可,因为这样就释放掉了其中一条记录的锁,以致于另一个事务可以正常地执行下去。
MySQL死锁解决方案
在MySQL中,死锁是如何解决的呢?一般来说,数据库系统提供了两种解决死锁的办法:死锁检测和死锁超时。
死锁检测是如何做到的呢?数据库会检测到存在循环依赖,这个时候就表示发生了死锁,因为没有一个资源的条件能得到满足。一般来说,InnoDB能够比较迅速地检测到死锁的存在,并立即返回一个错误给用户。这种解决方式非常的有效,能够有效地避免用户进行一些无效地查询,以及慢SQL的出现。
死锁超时是另一种非常常规的解决思路,就是当查询的时间超过多少秒的时候,数据库引擎放弃执行这条SQL,但是这种方式不太友好,会产生大量的重复查询,浪费数据库资源。
InnoDB目前的做法就是将数据库中持有最少行级排他锁的事务进行回滚,这样其它的事务就有机会去获取对应的资源。
死锁产生原因
死锁产生的原因主要有两个:数据的冲突和存储引擎实现方式不同。一般来说,死锁产生的时候只需要回滚其中一个或多个事务就可以打破死锁的局面,让其它事务继续进行下去。我们再额外地执行被回滚的事务即可。