mysql死锁学习第一篇

前言

    技术群早上有个兄台发了一个死锁的日志,我瞄了一眼,发现插入也会死锁,好奇让人变得更强大。

日志

    看下那位老哥的日志

------------------------
LATEST DETECTED DEADLOCK
------------------------
2019-12-20 04:00:03 0x7f78e455e700
*** (1) TRANSACTION:
TRANSACTION 3460338, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 2011281, OS thread handle 140156593497856, query id 29253160 10.105.232.16 DBopr update

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 956 page no 98724 n bits 520 index IDX_PN_ID of table `DB`.`TABLE_NAME` trx id 3460338 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 437 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 16; hex 38353130313031303030353531333238; asc 8510101000551328;;
1: len 1; hex 6e; asc n;;
2: len 8; hex 8000000000104ae2; asc       J ;;

*** (2) TRANSACTION:
TRANSACTION 3460340, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 2024731, OS thread handle 140157203638016, query id 29253163 10.105.232.16 DBopr update

*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 956 page no 98724 n bits 520 index IDX_PN_ID of table `DB`.`TABLE_NAME` trx id 3460340 lock_mode X locks gap before rec
Record lock, heap no 437 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 16; hex 38353130313031303030353531333238; asc 8510101000551328;;
1: len 1; hex 6e; asc n;;
2: len 8; hex 8000000000104ae2; asc       J ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 956 page no 98724 n bits 520 index IDX_PN_ID of table `DB`.`TABLE_NAME` trx id 3460340 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 437 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 16; hex 38353130313031303030353531333238; asc 8510101000551328;;
1: len 1; hex 6e; asc n;;
2: len 8; hex 8000000000104ae2; asc       J ;;

*** WE ROLL BACK TRANSACTION (2)

有点长,而且比较难懂。

解释
    第一个insert的时候idx索引上拿到x锁,lock_mode X locks gap before rec insert intention waiting
    第二个insert的时候lock_mode X locks gap before rec,也是跟gap有关系

划重点

gap

    看到上面总总情况,都跟gap有关系,那么我们就要了解下gap是什么东东。
个人理解:gap是意向锁,可以来解决幻读。为啥?你改完锁住,别人就不能改了,这样就不会幻读了。

官网解读
在这里插入图片描述
    我们可以看到gap也分共享锁何排他锁,如果是一个范围的话,会锁一个范围的。如果可以指定到特定行,那么gap就是一个行的。

参考官网

14.7.1 InnoDB锁定

insert导致死锁原因排查

参考网址

14.7.3通过InnoDB中的不同SQL语句设置的锁

gap锁在insert里面起到作用

在这里插入图片描述
    insert拿到共享的gap意向锁,然后再去拿X锁。在我看来,mysql根据gap去把控并发,而不是直接把MySQL锁去争抢。

    重要的一点:如果出现重复键错误,则会在重复索引记录上设置一个共享锁。如果有多个会话试图插入同一行(如果另一个会话已经具有互斥锁),则使用共享锁可能会导致死锁。

    我们再来理解一下上面这句话的意思:插入的时候会生成插入意图的gap锁,如果在不同范围不会互相阻塞。比如插入4,7跟插入5,6不会互相阻塞。但是一旦重复键重复冲突,则会在重复索引记录上设置一个共享锁。如果一个事务拿到共享锁,那么他们就都拿不到排他锁了。

重点

  1. 死锁的形成,一个事务拿了gap共享锁,也就是上面日志里面的idx索引里面的对应关系,这时它要去拿排他锁,凉了,排他和共享是不兼容的,阻塞住了。再看另一个事务,共享锁也没有拿到,排他锁也没有拿到,gg
  2. 为啥共享锁和排他锁不兼容?看下下面的图

在这里插入图片描述

发布了212 篇原创文章 · 获赞 30 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/weixin_38336658/article/details/103669389