mysql中行级锁的一些实验

看此文前先看 MySQL 中的锁机制,本文是看了该文后做的一些实验记录和总结,仅够参考,更多的是需要自己在mysql中做实验,理解。

总结

1、通过主键索引操作单个记录,只会对该主键索引记录加record lock;因此,此时只是不能修改该条记录。

2、通过唯一索引操作单个记录,会对改唯一索引记录加record lock,对该唯一索引对应的 主键索引记录加record lock;因此,此时只是不能修改该条记录

3、通过普通索引操作单个记录,会对该范围进行左延伸/右延伸 后,延伸后得到一个新范围;

  • 对新范围里的普通索引记录,加Next-key锁(record lock+gap lock);
  • 对该新范围里的主键索引记录加record lock;

因此,此时不能修改该条记录,也不能在新范围里插入新(普通索引)纪录

4、通过主键索引操作范围多个记录,会对该范围进行左延伸/右延伸,延伸后得到一个新范围;

  • 对新范围里的主键索引记录,加Next-key锁(record lock+gap lock)

因此,此时不能修改范围里的记录,也不能在新范围里插入新(主键索引)纪录

5、通过唯一索引操作范围多个记录,会对该范围进行左延伸/右延伸,延伸后得到一个新范围;

  • 对新范围里的唯一索引记录,加Next-key锁(record lock+gap lock)
  • 对新范围里的主键索引记录加record lock;

因此,此时不能修改范围里的记录,也不能在新范围里插入新(唯一索引)纪录

6、通过普通索引操作范围多个记录,同 5,因此,此时不能修改范围里的记录,也不能在新范围里插入新(普通索引)纪录

7、通过无索引操作单个记录或范围多个记录,会对所有的主键索引记录加即Next-key锁(record lock+gap lock)。因此,此时无法修改任何值、插入任何行

这也就是为什么 MySQL 推荐通过索引操作数据,最好是主键。


实验前的准备

mysql> create table t(
	  id int primary key,
	  c1 int,
	  c2 int,
	  c3 int
	);
mysql> create unique index idx_t_c1 on t(c1);
mysql> create index idx_t_c2 on t(c2);
mysql> insert into t(id,c1,c2,c3) values (1,1,2,3),(5,4,5,6),(9,7,8,9),(13,10,11,12);
mysql> select * from t;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  1 |    1 |    2 |    3 |
|  5 |    4 |    5 |    6 |
|  9 |    7 |    8 |    9 |
| 13 |   10 |   11 |   12 |
+----+------+------+------+
4 rows in set (0.00 sec)
mysql> desc t;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | NO   | PRI | NULL    |       |
| c1    | int(11) | YES  | UNI | NULL    |       |
| c2    | int(11) | YES  | MUL | NULL    |       |
| c3    | int(11) | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
4 rows in set (0.01 sec)
mysql> SET GLOBAL innodb_status_output=ON;
mysql> SET GLOBAL innodb_status_output_locks=ON;

对于select的语句中有范围

如果select的范围为 [a,b], 则会向左延伸,找第一个<=a的值;向右延伸,找第一个值>b的值,形成新的范围[a,d]或(c,d],锁住这之间的间隙;
举例:假设当前表中一个索引为id, 该索引的值有 1 5 9 13 ,其实就是前面创建的那张表。

select * from t;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  1 |    1 |    2 |    3 |
|  5 |    4 |    5 |    6 |
|  9 |    7 |    8 |    9 |
| 13 |   10 |   11 |   12 |
+----+------+------+------+
select * from t where id between 5 and 9 for update;  锁定[5],(5,9],(9,13],[5,13]
select * from t where id between 3 and 9 for update;  锁定(1,5],(5,9],(9,13],(1,13]
select * from t where id between 3 and 13 for update; 锁定(1,5],(5,9],(9,13],(13,+)(1,+)
select * from t where id between 3 and 15 for update; 锁定(1,5],(5,9],(9,13],(13,+)(1,+)
select * from t where id between 1 and 9 for update;  锁定[1],(1,5],(5,9],(9,13][1,13]
select * from t where id between 1 and 13 for update; 锁定[1],(1,5],(5,9],(9,13],(13,+)[1,+]
select * from t where id between 1 and 15 for update; 锁定[1],(1,5],(5,9],(9,13],(13,+)[1,+]
select * from t where id between 0 and 15 for update; 锁定(-,1],(1,5],(5,9],(9,13],(13,+)[-,+]

这个是为后面做准备的,看不懂没关系,先往下看,看到(4)的时候可以回来看这里。

(1)通过主键索引操作单个记录

mysql> begin;
mysql> SELECT * FROM t WHERE id = 5 FOR UPDATE;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  5 |    4 |    5 |    6 |
+----+------+------+------+
1 row in set (0.00 sec)
mysql> SHOW ENGINE INNODB STATUS;
---TRANSACTION 43298, ACTIVE 11 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 30, OS thread handle 11440, query id 429 localhost ::1 root starting
SHOW ENGINE INNODB STATUS
TABLE LOCK table `test`.`t` trx id 43298 lock mode IX
RECORD LOCKS space id 317 page no 3 n bits 72 index PRIMARY of table `test`.`t` trx id 43298 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 00000000a91d; asc       ;;
 2: len 7; hex d500000152011d; asc     R  ;;
 3: len 4; hex 80000004; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000006; asc     ;;

结果分析:存在 2 个锁结构(表IX锁、主键索引上的X记录锁),锁定了1条索引记录;

  • 表t上存在IX锁;
  • 主键索引上存在一个X记录锁,锁定了id为5的那条主键索引记录(主键索引记录包括该行全部数据)。

(2)通过唯一索引操作单个记录

  • c1是唯一索引
mysql> begin;
mysql> SELECT * FROM t WHERE c1 = 4 FOR UPDATE;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  5 |    4 |    5 |    6 |
+----+------+------+------+
1 row in set (0.00 sec)
mysql> SHOW ENGINE INNODB STATUS;
---TRANSACTION 43299, ACTIVE 10 sec
3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 30, OS thread handle 11440, query id 433 localhost ::1 root starting
SHOW ENGINE INNODB STATUS
TABLE LOCK table `test`.`t` trx id 43299 lock mode IX
RECORD LOCKS space id 317 page no 4 n bits 72 index idx_t_c1 of table `test`.`t` trx id 43299 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000004; asc     ;;
 1: len 4; hex 80000005; asc     ;;

RECORD LOCKS space id 317 page no 3 n bits 72 index PRIMARY of table `test`.`t` trx id 43299 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 00000000a91d; asc       ;;
 2: len 7; hex d500000152011d; asc     R  ;;
 3: len 4; hex 80000004; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000006; asc     ;;

结果分析:存在 3 个锁结构(表IX锁、主键索引上X记录锁、唯一索引上的X记录锁),锁定了2条索引记录;

  • 表t上存在IX锁;
  • 主键索引上存在一个X记录锁,锁定了id为5的主键索引记录(主键索引记录包括该行全部数据);
  • 索引idx_t_c1上存在一个X记录锁,锁定了c1为4的唯一索引记录(唯一索引记录中只包括id和c1两列)。

噢!它是先通过唯一索引idx_t_c1,由c1=4找到id=5,知道了id=5,再通过主键索引找到id=5的记录。
记录锁永远都是锁定索引记录,锁定非聚簇索引时会先锁定聚簇索引。
如果表中没有定义索引,InnoDB 默认为表创建一个隐藏的聚簇索引,并且使用该索引锁定记录。

(3)通过普通索引操作单个记录

  • c2为普通索引
mysql> begin;
mysql> SELECT * FROM t WHERE c2 = 5 FOR UPDATE;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  5 |    4 |    5 |    6 |
+----+------+------+------+
1 row in set (0.00 sec)
mysql> SHOW ENGINE INNODB STATUS;
---TRANSACTION 43480, ACTIVE 15 sec
4 lock struct(s), heap size 1136, 3 row lock(s)
MySQL thread id 53, OS thread handle 11440, query id 656 localhost ::1 root starting
SHOW ENGINE INNODB STATUS
TABLE LOCK table `test`.`t` trx id 43480 lock mode IX
RECORD LOCKS space id 318 page no 5 n bits 80 index idx_t_c2 of table `test`.`t` trx id 43480 lock_mode X
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 4; hex 80000005; asc     ;;

RECORD LOCKS space id 318 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 43480 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 00000000a9c8; asc       ;;
 2: len 7; hex c600000142011d; asc     B  ;;
 3: len 4; hex 80000004; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000006; asc     ;;

RECORD LOCKS space id 318 page no 5 n bits 80 index idx_t_c2 of table `test`.`t` trx id 43480 lock_mode X locks gap before rec
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000008; asc     ;;
 1: len 4; hex 80000009; asc     ;;

结果分析:存在4个锁结构(表IX锁、主键索引上X记录锁、普通索引上的X next-key锁、普通索引上的X间隙锁),锁定了3个索引记录;

  • 表 t 上存在 IX 锁,
  • 索引 idx_t_c2 上存在一个 next-key 锁(锁定了c2 (2, 5])
    索引 idx_t_c2 还有一个 X 间隙锁(c2 (5,8] 被锁定 );
  • 主键索引上存在一个 X 记录锁(id = 5的主键索引记录被锁定)。
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  1 |    1 |    2 |    3 |
|  5 |    4 |    5 |    6 |
|  9 |    7 |    8 |    9 |
| 13 |   10 |   11 |   12 |
+----+------+------+------+
--另一个事务
mysql> begin;
mysql> insert into t(id,c1,c2,c3) values (-1,-1,1,0);  			成功
mysql> insert into t(id,c1,c2,c3) values (-7,-7,2,0);  			成功
mysql> insert into t(id,c1,c2,c3) values (-3,-3,3,0);  			失败
mysql> insert into t(id,c1,c2,c3) values (-4,-4,4,0);  			失败
mysql> insert into t(id,c1,c2,c3) values (-5,-5,5,0);  			失败
mysql> insert into t(id,c1,c2,c3) values (-6,-6,7,0);  			失败
mysql> insert into t(id,c1,c2,c3) values (-2,-2,8,0);  			失败
mysql> insert into t(id,c1,c2,c3) values (7,-7,12,0);  			成功
mysql> rollback;

反正就是c2的值在(2,5],(5,8]之间的,都不能插入,对于c2为5的记录不能更新。

(4)通过主键索引操作范围多个记录

mysql> begin;
mysql> SELECT * FROM t WHERE id BETWEEN 3 and 10 FOR UPDATE;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  5 |    4 |    5 |    6 |
|  9 |    7 |    8 |    9 |
+----+------+------+------+
2 rows in set (0.00 sec)
mysql> SHOW ENGINE INNODB STATUS;
---TRANSACTION 43300, ACTIVE 9 sec
2 lock struct(s), heap size 1136, 3 row lock(s)
MySQL thread id 30, OS thread handle 11440, query id 437 localhost ::1 root starting
SHOW ENGINE INNODB STATUS
TABLE LOCK table `test`.`t` trx id 43300 lock mode IX
RECORD LOCKS space id 317 page no 3 n bits 72 index PRIMARY of table `test`.`t` trx id 43300 lock_mode X
Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 00000000a91d; asc       ;;
 2: len 7; hex d500000152011d; asc     R  ;;
 3: len 4; hex 80000004; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000006; asc     ;;

Record lock, heap no 4 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000009; asc     ;;
 1: len 6; hex 00000000a91d; asc       ;;
 2: len 7; hex d500000152012a; asc     R *;;
 3: len 4; hex 80000007; asc     ;;
 4: len 4; hex 80000008; asc     ;;
 5: len 4; hex 80000009; asc     ;;

Record lock, heap no 5 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 8000000d; asc     ;;
 1: len 6; hex 00000000a91d; asc       ;;
 2: len 7; hex d5000001520137; asc     R 7;;
 3: len 4; hex 8000000a; asc     ;;
 4: len 4; hex 8000000b; asc     ;;
 5: len 4; hex 8000000c; asc     ;;

结果分析:存在2个锁结构(表IX锁、主键索引上X next-key锁),锁定了3条记录;

  • 表t上存在IX锁;
  • 主键索引上存在3个X Next-key锁( (1, 5]、(5, 9]、(9,13]被锁定 );
    (此时,只可以插入id小于1和大于13的数据;)
-- 另一个事务
mysql> begin;
mysql> insert into t(id,c1,c2,c3) values (0,0,0,0);  			成功
mysql> update t set c1 = 111 where id = 1; 						成功
mysql> insert into t(id,c1,c2,c3) values (2,222,222,222);  		失败
mysql> insert into t(id,c1,c2,c3) values (3,333,333,333); 	 	失败
mysql> insert into t(id,c1,c2,c3) values (4,444,444,444); 		失败
mysql> update t set c1 = 555 where id = 5; 						失败
mysql> insert into t(id,c1,c2,c3) values (8,888,888,888);  		失败
mysql> insert into t(id,c1,c2,c3) values (10,100,100,100);  	失败
mysql> insert into t(id,c1,c2,c3) values (11,1111,1111,1111); 	失败
mysql> insert into t(id,c1,c2,c3) values (12,1222,1222,1222); 	失败
mysql> update t set c1 = 1333 where id = 13; 					失败
mysql> insert into t(id,c1,c2,c3) values (14,1444,1444,1444); 	成功
mysql> rollback;

再举一个例子:

mysql> begin;
mysql> SELECT * FROM t WHERE id BETWEEN 3 and 15 FOR UPDATE;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  5 |    4 |    5 |    6 |
|  9 |    7 |    8 |    9 |
| 13 |   10 |   11 |   12 |
+----+------+------+------+
3 rows in set (0.00 sec)
mysql> SHOW ENGINE INNODB STATUS;
---TRANSACTION 43336, ACTIVE 11 sec
2 lock struct(s), heap size 1136, 4 row lock(s)
MySQL thread id 49, OS thread handle 19320, query id 495 localhost ::1 root starting
SHOW ENGINE INNODB STATUS
TABLE LOCK table `test`.`t` trx id 43336 lock mode IX
RECORD LOCKS space id 317 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 43336 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 00000000a91d; asc       ;;
 2: len 7; hex d500000152011d; asc     R  ;;
 3: len 4; hex 80000004; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000006; asc     ;;

Record lock, heap no 4 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000009; asc     ;;
 1: len 6; hex 00000000a91d; asc       ;;
 2: len 7; hex d500000152012a; asc     R *;;
 3: len 4; hex 80000007; asc     ;;
 4: len 4; hex 80000008; asc     ;;
 5: len 4; hex 80000009; asc     ;;

Record lock, heap no 5 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 8000000d; asc     ;;
 1: len 6; hex 00000000a91d; asc       ;;
 2: len 7; hex d5000001520137; asc     R 7;;
 3: len 4; hex 8000000a; asc     ;;
 4: len 4; hex 8000000b; asc     ;;
 5: len 4; hex 8000000c; asc     ;;
  • 主键索引上存在4个X Next-key锁(id (1,5]、(5, 9]、(9,13]、(13, +无穷)被锁定);
-- 另一个事务
mysql> begin;
mysql> insert into t(id,c1,c2,c3) values (0,0,0,0);  			成功
mysql> update t set c1 = 111 where id = 1; 						成功
mysql> insert into t(id,c1,c2,c3) values (2,222,222,222);  		失败
mysql> insert into t(id,c1,c2,c3) values (22,2222,2222,2222);  	失败
mysql> rollback;

(5)通过唯一索引操作范围多个记录

mysql> begin;
mysql> SELECT * FROM t WHERE c1 BETWEEN 3 and 9 FOR UPDATE;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  5 |    4 |    5 |    6 |
|  9 |    7 |    8 |    9 |
+----+------+------+------+
2 rows in set (0.00 sec)
mysql> SHOW ENGINE INNODB STATUS;
---TRANSACTION 43378, ACTIVE 11 sec
3 lock struct(s), heap size 1136, 5 row lock(s)
MySQL thread id 53, OS thread handle 11440, query id 554 localhost ::1 root starting
SHOW ENGINE INNODB STATUS
TABLE LOCK table `test`.`t` trx id 43378 lock mode IX
RECORD LOCKS space id 317 page no 4 n bits 80 index idx_t_c1 of table `test`.`t` trx id 43378 lock_mode X
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000004; asc     ;;
 1: len 4; hex 80000005; asc     ;;

Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000007; asc     ;;
 1: len 4; hex 80000009; asc     ;;

Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 8000000a; asc     ;;
 1: len 4; hex 8000000d; asc     ;;

RECORD LOCKS space id 317 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 43378 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 00000000a91d; asc       ;;
 2: len 7; hex d500000152011d; asc     R  ;;
 3: len 4; hex 80000004; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000006; asc     ;;

Record lock, heap no 4 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000009; asc     ;;
 1: len 6; hex 00000000a91d; asc       ;;
 2: len 7; hex d500000152012a; asc     R *;;
 3: len 4; hex 80000007; asc     ;;
 4: len 4; hex 80000008; asc     ;;
 5: len 4; hex 80000009; asc     ;;

结果分析:存在3个锁结构,锁定了5条索引记录;

  • 表t上存在IX锁;
  • 主键索引上存在2个X 记录锁(id为5、9的主键索引记录被锁定,即c2为4和7的记录不能被修改了)
  • 唯一索引上存在3个X Next-key锁(c1 (1, 4]、(4, 7]、(7, 10]被锁定),
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  1 |    1 |    2 |    3 |
|  5 |    4 |    5 |    6 |
|  9 |    7 |    8 |    9 |
| 13 |   10 |   11 |   12 |
+----+------+------+------+
--另一个事务
mysql> begin;
mysql> insert into t(id,c1,c2,c3) values (-1,0,0,0);  			成功
mysql> insert into t(id,c1,c2,c3) values (0,3,0,0);  			失败
mysql> insert into t(id,c1,c2,c3) values (6,-1,0,0);  			成功
mysql> insert into t(id,c1,c2,c3) values (8,22,0,0);  			成功
mysql> insert into t(id,c1,c2,c3) values (22,8,0,0);  			失败
mysql> update t set c2 = 0 where c1 = 1; 						成功  
mysql> update t set c2 = 0 where c1 = 4; 						失败  
mysql> update t set c2 = 0 where c1 = 2; 						成功,因为锁的是间隙,不是索引记录(因为并没有这条记录,所以实际上什么都没有改变)
mysql> update t set c2 = 0 where c1 = 10; 						失败,不能通过c1改变c1=10这条记录的其他值
mysql> update t set c2 = 0 where id = 13; 						成功,但是可以通过id改变c1=10的这条记录
mysql> rollback;

反正就是c1的值在(1,4],(4,7],(7,10]之间的,都不能插入,对于c1为4、7的记录不能更新。
c1的10的记录可以更新,但是不能通过c1改变c1=10这条记录的其他值,可以通过id改变c1=10的这条记录

(6)通过普通索引操作范围多个记录

同(5)

(7)通过无索引操作单个记录或范围多个记录

mysql> begin;
mysql> SELECT * FROM t WHERE c3 = 6 FOR UPDATE;SELECT * FROM t WHERE c3 BETWEEN 4 and 10 FOR UPDATE;+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  5 |    4 |    5 |    6 |
+----+------+------+------+
mysql> SHOW ENGINE INNODB STATUS;
---TRANSACTION 43513, ACTIVE 14 sec
2 lock struct(s), heap size 1136, 5 row lock(s)
MySQL thread id 53, OS thread handle 11440, query id 730 localhost ::1 root starting
SHOW ENGINE INNODB STATUS
TABLE LOCK table `test`.`t` trx id 43513 lock mode IX
RECORD LOCKS space id 318 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 43513 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 6; hex 00000000a9c8; asc       ;;
 2: len 7; hex c6000001420110; asc     B  ;;
 3: len 4; hex 80000001; asc     ;;
 4: len 4; hex 80000002; asc     ;;
 5: len 4; hex 80000003; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 00000000a9c8; asc       ;;
 2: len 7; hex c600000142011d; asc     B  ;;
 3: len 4; hex 80000004; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000006; asc     ;;

Record lock, heap no 4 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000009; asc     ;;
 1: len 6; hex 00000000a9c8; asc       ;;
 2: len 7; hex c600000142012a; asc     B *;;
 3: len 4; hex 80000007; asc     ;;
 4: len 4; hex 80000008; asc     ;;
 5: len 4; hex 80000009; asc     ;;

Record lock, heap no 5 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 8000000d; asc     ;;
 1: len 6; hex 00000000a9c8; asc       ;;
 2: len 7; hex c6000001420137; asc     B 7;;
 3: len 4; hex 8000000a; asc     ;;
 4: len 4; hex 8000000b; asc     ;;
 5: len 4; hex 8000000c; asc     ;;

结果分析:存在2个锁结构,锁定了5个索引项;

  • 表t上存在IX锁,
  • 主键索引上存在5个next-key锁,锁定了所有的主键范围((-∞,1], (1,5],(5,9],(9,13],(13,+∞)。

此时其他事务无法插入任何数据。 不仅无法修改c3=6的那条记录,其他所有记录都无法修改。

--另一个事务
mysql> begin;
mysql> insert into t(id,c1,c2,c3) values (-1,-1,1,0);  			失败
mysql> insert into t(id,c1,c2,c3) values (20,-2,2,0);  			失败
mysql> update t set c2 = 0 where c3 = 6; 						失败
mysql> update t set c2 = 0 where c3 = 9; 						失败
mysql> update t set c2 = 0 where id = 9; 						失败
mysql> rollback;

也就是说这个时候,不能够执行任何写操作。

死锁

mysql> select * from t;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  1 |    1 |    2 |    3 |
|  5 |    4 |    5 |    6 |
|  9 |    7 |    8 |    9 |
| 13 |   10 |   11 |   12 |
+----+------+------+------+
4 rows in set (0.00 sec)

--事务T1												--事务T2
mysql> begin;											mysql> begin;			
mysql> select * from t where id=22 for update;
Empty set (0.00 sec) 		

														mysql> select * from t where id=23 for update;
														Empty set (0.00 sec)
												
														mysql> insert into t(id,c1,c2,c3) values (23,-2,2,0); 	
												
mysql> insert into t(id,c1,c2,c3) values (22,-1,1,0); 
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
														
														Query OK, 1 row affected (10.77 sec)

因为事务T1获得了(13,+∞)的间隙锁,事务T2也获得(13,+无穷大)的间隙锁(因为最大ID是13,锁13之后的间隙,间隙锁之间不互斥)。T2想要插入id=23的记录,但是间隙被T1锁了;T1想要插入id=22的记录,但是间隙被T2锁了;就造成了死锁。
从上面实验可以看出,mysql检测到死锁后,就把是T1给关闭了,然后T2才能成功插入数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值