MySQL死锁和避免死锁

概念

死锁是指两个或两个以上事务在执行过程中因争抢锁资源而造成的互相等待的现象。

产生死锁的四个必要条件:

(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

死锁举例

事务1 (图1)和事务2(图2)用lock in share mode 锁住表test3,事务1想要获取排它锁被阻塞,事务2也想获取排它锁时因争夺同一资源产生死锁导致事务1停止运行等待,事务2运行成功。
在第3步的时候一直等待直到超时。
在低6步的时候等待,并且此时事务2争夺资源,事务2执行成功,事务1停止运行。

发生死锁后,InnoDB一般都可以检测到,并使一个事务释放锁回退,另一个则可以获取锁完成事务。
《最详细的MySQL锁(悲观锁 乐观锁 共享锁 排它锁等)讲解》这篇文件讲了lock in share mode 的用法。
在这里插入图片描述
在这里插入图片描述

MySQL解决死锁的方法

超时等待:即当两个事务互相等待时,当一个事务等待时间超过设置的阈值(innodb_lock_wait_timeout设置其阈值)时,就将其回滚,另外事务继续进行。(缺点:如果回滚的事务更新了很多行,占用了较多的undo log,这是采用FIFO的方式(先进先出),就不太合适,因为这个事务回滚花费的时间比另外一个的事务回滚花费的时间可能还要多);

wait-for graph(等待图):死锁碰撞检测,是一种较为主动的死锁检测机制,要求数据库保存锁的信息链表和事务等待链表两部分信息,通过这两个部分信息构造出一张图,在每个事务请求锁并发生等待时都会判断是否存在回路,如果在图中检测到回路,就表明有死锁产生,这时候InnoDB存储引擎会选择回滚undo量最小的事务。InnoDB存储采用这种方式实现。

下面举个例子简单介绍下对wait-for graph的理解。
原文:https://blog.csdn.net/noaman_wgs/article/details/82529908
如下图所示,有4个事务T1、T2、T3、T4,由图2可以得出T2对row1占用x锁;由图3得出T1对row2占用s锁(遵循FIFO原则,链表最上层先拿到锁资源,故T2、T1分别占有row1、row2的锁资源)。

现在:
(1)T1想要占用row1的s锁,T1需要等待T2的x锁释放(图1、2)
(2)T2想要占用row2的x锁,T2需要等待T1、T4的s锁释放(图1、3)
(3)T3想要占用row2的x锁,T3需要等待T1、T4的s锁和T2的x锁释放(图1、3)
在这里插入图片描述
根据上面的信息,可以绘制wait-for graph:
有4个事务,所以对应4个节点T1、T2、T3、T4;
由(1)得出:节点T1指向节点T2;
由(2)得出:节点T2分别指向节点T1、T4;
由(3)得出:节点T3指向节点T1、T2、T4;
在这里插入图片描述
由上图可知,T1、T2之间存在回路,所以存在死锁。

查看MySQL出现的Deadlock日志

show engine innodb status

在这里插入图片描述

避免死锁

  • 为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增加。
  • 多个程序尽量约定以相同的顺序访问表(这也是解决并发理论中哲学家就餐问题的一种思路),以固定的顺序访问表和行。比如两个更新数据的事务,事务A更新数据的顺序为1,2;事务B更新数据的顺序为 2 ,1,这样更可能会造成死锁。
  • 同一个事务尽可能做到一次锁定所需要的所有资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值