美文网首页
MySQL:死锁模拟

MySQL:死锁模拟

作者: 重庆八怪 | 来源:发表于2023-02-28 16:38 被阅读0次

这个问题的关键在于sup伪列上的S锁放大,线上肯定是无序的因此block不一定是最后一个,这里就用顺序来模拟

建表:
CREATE TABLE `test3` (
`id1` int NOT NULL AUTO_INCREMENT,
`id2` int DEFAULT NULL,
 `a` int DEFAULT NULL,
 PRIMARY KEY (`id1`),
  UNIQUE KEY `a` (`a`,`id1`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
Query OK, 0 rows affected, 1 warning (0.05 sec)

mysql> set auto_increment_increment=10;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test3(id2,a) values(1,1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 8 rows affected (0.01 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 16 rows affected (0.01 sec)
Records: 16  Duplicates: 0  Warnings: 0

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 32 rows affected (0.01 sec)
Records: 32  Duplicates: 0  Warnings: 0

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 64 rows affected (0.02 sec)
Records: 64  Duplicates: 0  Warnings: 0

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 128 rows affected (0.03 sec)
Records: 128  Duplicates: 0  Warnings: 0

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 256 rows affected (0.05 sec)
Records: 256  Duplicates: 0  Warnings: 0

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 512 rows affected (0.11 sec)
Records: 512  Duplicates: 0  Warnings: 0

mysql> insert into test3(id2,a) select id2,a from test3;
Query OK, 1024 rows affected (0.22 sec)
Records: 1024  Duplicates: 0  Warnings: 0

mysql> alter table test3 change id1 id1 int NOT NULL ;
Query OK, 2048 rows affected (0.51 sec)
Records: 2048  Duplicates: 0  Warnings: 0

mysql> alter table test3 drop primary key;
Query OK, 2048 rows affected (0.58 sec)
Records: 2048  Duplicates: 0  Warnings: 0

mysql> alter table test3 add primary key(id1,id2);
Query OK, 0 rows affected (0.15 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table test3 add key(a);
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> update test3 set id2=id1 ,a=id1;
Query OK, 2047 rows affected (1.41 sec)
Rows matched: 2048  Changed: 2047  Warnings: 0

表建立好以后,总共3列,其中id1,id2为主键,a,id1为唯一键,数据处理好以后主键唯一键都是有序的,而线上可能是乱序的。而自增的步长改为了10,记录从1,11,21开始,那么最后几条记录如下:

+-------+-------+-------+
| 30511 | 30511 | 30511 |
| 30521 | 30521 | 30521 |
| 30531 | 30531 | 30531 |
| 30541 | 30541 | 30541 |
| 30551 | 30551 | 30551 |
| 30561 | 30561 | 30561 |
| 30571 | 30571 | 30571 |
| 30581 | 30581 | 30581 |
| 30591 | 30591 | 30591 |
| 30601 | 30601 | 30601 |
+-------+-------+-------+

时序如下:

session1 session2 session3
begin;
insert into test3 values(119,119,30610);
这一步的目的主要是在唯一键a,id1最后插入一行数据
begin;
insert into test3 values(119,219,30610),(6059,6059,6059);(堵塞)
这一步完成后虽然有两个insert的值,但是第二个数据并没有进行唯一性检查和插入,而是堵塞在第一行数据,第一行数据,主键和session1是没有冲突的,但是唯一键有冲突,因此实际等待点为第一行数据(119,219,30610)对唯一键冲突检测上
begin;
insert into test3 values(6059,6071,6059);(不堵塞完成)
完成这一步我们插入了一行数据,目的在于后面堵塞session2语句的第二行数据在唯一键索引上的数据插入,这里我们可以看到主键是不冲突的,但是唯一键都是6059,6059,因此后面会冲突
rollback;
完成这一步的目的在于让session2的lock s 扩展到唯一键的最后一个block的sup伪列上,为next key lock
注意:这个时候session2的第一行数据插入实际上已经完成,并且有一个lock S到sup伪列上,这个时候堵塞在第二行数据的6059,6059这个唯一键上,而这个锁的持有者为session3
insert into test3 values(119,319,30620);
完成这一步的目的在于让session3也堵被session2堵塞,这个时候插入的唯一键只要落到最后一行记录到sup伪列之间则会被堵塞,这里插入的是唯一键30620,119

模拟中session3,没有使用insert values(),()的方式,是因为如果这样2行记录都会插入成功,因为线上是并发的,因此即便insert values(),()也可能出现问题这是其一。

其二,如果insert的值过多则持有锁的时间就更长,触发这个问题的机会就更大。因为insert values(),(),()....实际上还是每个行数据分别进行唯一性检查,插入操作,但是节省了语法解析和优化的部分。得到的死锁记录如下:

*** (1) TRANSACTION:
TRANSACTION 2752736, ACTIVE 111 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 7 lock struct(s), heap size 1200, 5 row lock(s), undo log entries 2
MySQL thread id 26237, OS thread handle 140736551307008, query id 2964 localhost root update
insert into test106 values(119,219,30610),(6059,6059,6059)

*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 1639 page no 15 n bits 800 index a of table `t10`.`test106` trx id 2752736 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;


*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1639 page no 10 n bits 952 index a of table `t10`.`test106` trx id 2752736 lock mode S waiting
Record lock, heap no 441 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 800017ab; asc     ;;
 1: len 4; hex 800017ab; asc     ;;
 2: len 4; hex 800017b7; asc     ;;


*** (2) TRANSACTION:
TRANSACTION 2752739, ACTIVE 39 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1200, 3 row lock(s), undo log entries 2
MySQL thread id 26239, OS thread handle 140736283956992, query id 2970 localhost root update
insert into test106 values(119,319,30620)

*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 1639 page no 10 n bits 952 index a of table `t10`.`test106` trx id 2752739 lock_mode X locks rec but not gap
Record lock, heap no 441 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 800017ab; asc     ;;
 1: len 4; hex 800017ab; asc     ;;
 2: len 4; hex 800017b7; asc     ;;


*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1639 page no 15 n bits 800 index a of table `t10`.`test106` trx id 2752739 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

从死锁模型来看和线上一致。

相关文章

  • 死锁模拟

    死锁解释 死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象, 若无外力干涉那它们都将...

  • MySQL笔记-锁、事务与并发控制

    MySQL服务器逻辑架构 MySQL并发控制 MySQL死锁问题 MySQL中的事务

  • mysql死锁-非主键索引更新引起的死锁

    [mysql死锁-非主键索引更新引起的死锁] 背景:最近线上经常抛出mysql的一个Deadlock,细细查来,长...

  • 一则由于索引导致的MySQL死锁分析

    涉及死锁的 authorized_user 表的 DDL 死锁日志 根据 MySQL 日志分析出来的涉及死锁的 S...

  • 模拟 SQLSERVER 死锁

    环境: sqlserver 2008 事务(进程 ID (n))与另一个进程被死锁在锁资源上,并且已被选作死锁牺牲...

  • MySQL死锁案例分析一(先delete,再insert,导致死

    一、死锁案例 MySQL版本:Percona MySQL Server 5.7.19隔离级别:可重复读(RR)业务...

  • mysql简单排查&终止死锁线程 2022-03-29

    mysql简单排查&终止死锁线程 INFORMATION_SCHEMA MySQL把INFORMATION_SCH...

  • MySQL -- 死锁

    死锁: 死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象,当多个事务...

  • MySQL死锁

    死锁大家应该不会陌生,互相占用对方资源,互相等待释放,从而产生恶性循环,在数据库中当多个事务试图以不同的顺序来锁定...

  • mysql 死锁

    简介 死锁是两个或者多个竞争的操作在等待其他操作完成.死锁发生有 4 个条件:1: 互斥: 在一个时间点只有一个进...

网友评论

      本文标题:MySQL:死锁模拟

      本文链接:https://www.haomeiwen.com/subject/qdulldtx.html