死锁总结

死锁的必要条件

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

 以上解释稍显苦涩,翻译一下就是:       

      必须存在多个并发进程(事务)

      每个事务都持有了锁

      每个事务还需要继续持有其它锁

      每个事务还需持有的锁恰是其它事务占有的锁,并且一直循环等待。            

一般死锁

            每个事务执行两条SQL,分别持有了一把锁,然后加另一把锁,产生死锁。   

多数情况死锁示例

事务1 已经持有了order_id = 1 的X锁 ,试图获得order_id= 5的X锁,但此锁已被事务2 占有 , 同时事务2 已经持有了order_id = 5 的X锁 ,试图获得order_id= 1的X锁,但此锁已被事务1 占有了。 因此进入了一种互等状态,死锁产生。 

回滚导致死锁

回滚导致死锁示例

       order_id是唯一索引, 事务1, 事务2 , 事务3 都执行相同的操作,但事务1 后来执行了回滚操作,  事务2 和事务3 造成死锁。

       当事务1中插入一条记录的时候,这个会持有插入记录的行锁即X锁,当其它事务2, 事务3 再次插入相同的记录的时候,就会申请S锁(首先执行冲突检查),即事务2 和事务3 都申请到了S锁, 事务1 回滚以后,释放资源,这时事务2 和事务3 都持有了S锁,都申请加X锁,此时产生死锁。

 

间隙锁导致死锁

     order_id 是唯一索引,但非主键, 先查看表中内容  select order_id from mtp_order ;   即表中仅存在 order_id= 1, 5, 9 这样三条记录。

order_id

1
5
9
 

间隙锁导致死锁

      order_id是唯一索引, 事务1, 事务2分别先加gap锁,  事务1执行插入操作,但事务2 已在1,5之间加gap锁,所以被阻塞,当事务2执行插入时,因为事务1中在1,5之间加gap锁,因此产生死锁。

     

隐式锁(锁膨胀)死锁

 

锁膨胀导致死锁

 

        

       事务1 和事务2 并发执行相同的sql语句, 发生死锁。  事务1中先执行后面的子select语句, 加隐式S锁, 这时事务2中也开始执行后面的select语句, 因事务1中已经加过隐式锁,所以事务2中此时加的是显示S锁,相当于执行了锁升级(锁膨胀),此时事务1再执行的时候就会申请X锁, 因为事务2中已经存在S锁,因此申请未成功,同样事务2也不能执行,造成死锁。 具体可通过 show  engine innodb status  查看事务状态。  以及到表中innodb_lock_waits和innodb_locks中进行锁状态查询。

 

索引merge导致死锁

      什么是索引merge: 操作时,引擎层面同时走了两条索引(时间上可能有先后),将索引结果进行merge操作,然后返回给Server层 。

     示例: (refund_number 和user_id 分别为二级非唯一索引) ,且区分度差不多,如下图所示。

索引merge示例

索引merge导致死锁

 

 

避免死锁的技巧

     1: 以固定的顺序访问表和行

     2: 大事务拆小事务,大事务更加倾向于死锁。

     3: 为表添加合理的索引

     4: 降低事务隔离级别,如RR降到RC

     5: 尽量一次申请到所有的资源。

     6: 更新或者删除操作之前都确定记录是存在的,然后再做操作。

死锁检测: 等待图(属于有向图)。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值