MySQL中的锁3-行锁的实现

行锁的实现

在Innodb存储引擎中,行锁有3种实现方式,分别是:

  • Record Lock
  • Gap Lock
  • Next-Key Lock

Record Lock锁住单个记录,并且Record Lock总是会去锁主索引记录,如果建表时没有设置任何索引,则Innodb会隐式的创建一个主键并进行锁定;
Gap Lock锁住的是一个范围,但是不包含记录本身;
Next-Key Lock=Gap Lock+Record Lock,锁定包含记录本身的范围,所以Next-Key Lock是一种特殊的Gap Lock。

例如,a表中只有记录 2、 5 、 9,且在记录5上加锁。看下针对上面行锁三种不同的实现方式是如何具体加锁的。

  1. Record Lock只会锁住记录5本身;
  2. Gap Lock锁住范围(2,5),不包括边界,依然可以对记录2和5进行修改或删除,但是不能插入3、4等在锁住范围的值;
  3. Next-Key Lock锁住(2,5]范围,不包括记录2但是包括记录5本身。不能插入在2-5之间的数,可以删除或修改记录2,但是记录5不能修改和删除。

Next-Key Lock主要是用来防止幻读。在Innodb中,Repeatable-Read隔离级别大量使用了Next-Key Lock和Gap Lock,而Read-Committed隔离级别使用的行锁基本都是Record Lock。

在查询的列是唯一索引且查询条件是等值查询时,Next-Key Lock会降级为Record Lock。

简单SQL语句的加锁分析

首先要清楚无法单纯就一条SQL语句分析出其加锁情况,必须还要知道该SQL的一些前提条件,这些前提条件包括:(insert\delete\update操作都会隐式地包含一个查询操作,所以这里我把SQL语句中where条件中的列称之为查询列)

  • 当前事务的隔离级别是什么;
  • 查询列是不是主键;
  • 查询列上是否有二级索引;
  • 查询列上有二级索引的话,该索引是否唯一。

基于上面的前提条件,我们来分析如下情况:

  1. RC隔离级别下,查询列是主键;
  2. RC隔离级别下,查询列是二级唯一索引;
  3. RC隔离级别下,查询列是二级非唯一索引;
  4. RC隔离级别下,查询列上没有索引;
  5. RR隔离级别下,查询列是主键;
  6. RR隔离级别下,查询列是二级唯一索引;
  7. RR隔离级别下,查询列是二级非唯一索引;
  8. RR隔离级别下,查询列上没有索引;

针对上面列举的情况,我们通过查询语句+for update来演示,每种情况下演示分别等值查询和范围查询。

数据准备

mysql> show create table t3\G;
*************************** 1. row ***************************
       Table: t3
Create Table: CREATE TABLE `t3` (
  `a` int(11) NOT NULL,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`a`),
  UNIQUE KEY `b` (`b`),
  KEY `c` (`c`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

mysql> select * from t3;
+---+------+------+------+
| a | b    | c    | d    |
+---+------+------+------+
| 1 |    3 |    5 |    7 |
| 3 |    5 |    7 |    9 |
| 5 |    7 |    9 |   11 |
| 7 |    9 |   11 |   13 |
+---+------+------+------+
1. RC隔离级别下,查询列是主键

select * from t3 where a =3 for update;
此种情况会在a=3的记录上加record lock

---TRANSACTION 4393, ACTIVE 21 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 162 localhost root
TABLE LOCK table `test`.`t3` trx id 4393 lock mode IX
RECORD LOCKS space id 39 page no 3 n bits 80 index PRIMARY of table `test`.`t3` trx id 4393 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 80000003; asc     ;; --第一个字段是主键3,占用4个字节,被锁住了
 1: len 6; hex 000000000f70; asc      p;; --该字段为6个字节的事务id,这个id表示最近一次被更新的事务id
 2: len 7; hex cc00000157011c; asc     W  ;; --该字段为7个字节的回滚指针,用于mvcc
 3: len 4; hex 80000005; asc     ;; --该字段表示的是此记录的第二个字段5
 4: len 4; hex 80000007; asc     ;; --该字段表示的是此记录的第三个字段7
 5: len 4; hex 80000009; asc     ;; --该字段表示的是此记录的第四个字段9

select * from t3 where a <=3 for update;
此情况下,会加两个record lock锁住a=1和a=3的记录,具体如下:

---TRANSACTION 4394, ACTIVE 5 sec
2 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 166 localhost root
TABLE LOCK table `test`.`t3` trx id 4394 lock mode IX
RECORD LOCKS space id 39 page no 3 n bits 80 index PRIMARY of table `test`.`t3` trx id 4394 lock_mode X locks rec but not gap
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 000000000f70; asc      p;;
 2: len 7; hex cc000001570110; asc     W  ;;
 3: len 4; hex 80000003; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000007; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;

2. RC隔离级别下,查询列是二级唯一索引

select * from t3 where b =5 for update;
此情况会有2把锁,b=5的二级索引上,a=3(b=5)的聚集索引上,具体如下:

---TRANSACTION 4400, ACTIVE 7 sec
3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 174 localhost root
TABLE LOCK table `test`.`t3` trx id 4400 lock mode IX
RECORD LOCKS space id 39 page no 4 n bits 80 index b of table `test`.`t3` trx id 4400 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 80000005; asc     ;; -- 二级索引  key=5
 1: len 4; hex 80000003; asc     ;; -- value = 3(主键)

RECORD LOCKS space id 39 page no 3 n bits 80 index PRIMARY of table `test`.`t3` trx id 4400 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 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;

select * from t3 where b <=5 for update;
此情况下会产生5把record lock,二级索引(b=3、b=5、b=7)3把,聚集索引(a=1,a=3)2把,具体如下:

---TRANSACTION 4401, ACTIVE 6 sec
3 lock struct(s), heap size 1136, 5 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 180 localhost root
TABLE LOCK table `test`.`t3` trx id 4401 lock mode IX
RECORD LOCKS space id 39 page no 4 n bits 80 index b of table `test`.`t3` trx id 4401 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 4; hex 80000001; asc     ;;

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 80000003; 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 80000005; asc     ;;

RECORD LOCKS space id 39 page no 3 n bits 80 index PRIMARY of table `test`.`t3` trx id 4401 lock_mode X locks rec but not gap
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 000000000f70; asc      p;;
 2: len 7; hex cc000001570110; asc     W  ;;
 3: len 4; hex 80000003; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000007; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;
3. RC隔离级别下,查询列是二级非唯一索引

select * from t3 where c = 7 for update;
此情况下,有两把record lock,c=7对应的二级索引上和a=3对应的聚集索引上。

---TRANSACTION 4402, ACTIVE 109 sec
3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 184 localhost root
TABLE LOCK table `test`.`t3` trx id 4402 lock mode IX
RECORD LOCKS space id 39 page no 5 n bits 80 index c of table `test`.`t3` trx id 4402 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 80000007; asc     ;;
 1: len 4; hex 80000003; asc     ;;

RECORD LOCKS space id 39 page no 3 n bits 80 index PRIMARY of table `test`.`t3` trx id 4402 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 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;

select * from t3 where c <= 7 for update;
此情况下,有5把record lock。二级索引(c=5、c=7、c=9)3把,聚集索引(a=1,a=3)2把

---TRANSACTION 4403, ACTIVE 3 sec
3 lock struct(s), heap size 1136, 5 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 189 localhost root
TABLE LOCK table `test`.`t3` trx id 4403 lock mode IX
RECORD LOCKS space id 39 page no 5 n bits 80 index c of table `test`.`t3` trx id 4403 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 4; hex 80000001; asc     ;;

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

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

RECORD LOCKS space id 39 page no 3 n bits 80 index PRIMARY of table `test`.`t3` trx id 4403 lock_mode X locks rec but not gap
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 000000000f70; asc      p;;
 2: len 7; hex cc000001570110; asc     W  ;;
 3: len 4; hex 80000003; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000007; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;
4. RC隔离级别下,查询列上没有索引

select * from t3 where d = 9 for update;
此情况下,由于d列上没有索引,而锁是加在索引上的,所以只会在a=3的聚集索引上加1把record lock,具体如下:

---TRANSACTION 4405, ACTIVE 5 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 194 localhost root
TABLE LOCK table `test`.`t3` trx id 4405 lock mode IX
RECORD LOCKS space id 39 page no 3 n bits 80 index PRIMARY of table `test`.`t3` trx id 4405 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 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;

select * from t3 where d <= 9 for update;
此情况下,加2把record lock,锁加载a=1(d=7)和a=3(d=9)对应的聚集索引上,具体如下:

---TRANSACTION 4407, ACTIVE 2 sec
2 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 200 localhost root
TABLE LOCK table `test`.`t3` trx id 4407 lock mode IX
RECORD LOCKS space id 39 page no 3 n bits 80 index PRIMARY of table `test`.`t3` trx id 4407 lock_mode X locks rec but not gap
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 000000000f70; asc      p;;
 2: len 7; hex cc000001570110; asc     W  ;;
 3: len 4; hex 80000003; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000007; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;
5. RR隔离级别下,查询列是主键

select * from t3 where a =3 for update;
加a=3的记录上加记录锁(lock_mode X locks rec but not gap),具体如下:

2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 61 localhost root
TABLE LOCK table `test`.`t3` trx id 4365 lock mode IX
RECORD LOCKS space id 39 page no 3 n bits 72 index PRIMARY of table `test`.`t3` trx id 4365 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 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;

select * from t3 where a <= 5 for update;
会加多个范围区间的next-key lock(lock_mode X),具体如下:

---TRANSACTION 4367, ACTIVE 41 sec
2 lock struct(s), heap size 1136, 4 row lock(s)
RECORD LOCKS space id 39 page no 3 n bits 72 index PRIMARY of table `test`.`t3` trx id 4367 lock_mode X
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 000000000f70; asc      p;;
 2: len 7; hex cc000001570110; asc     W  ;;
 3: len 4; hex 80000003; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000007; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;

Record lock, heap no 4 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 000000000f75; asc      u;;
 2: len 7; hex cf0000015a0110; asc     Z  ;;
 3: len 4; hex 80000007; asc     ;;
 4: len 4; hex 80000009; asc     ;;
 5: len 4; hex 8000000b; asc     ;;

Record lock, heap no 5 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000007; asc     ;;
 1: len 6; hex 000000000f75; asc      u;;
 2: len 7; hex cf0000015a011c; asc     Z  ;;
 3: len 4; hex 80000009; asc     ;;
 4: len 4; hex 8000000b; asc     ;;
 5: len 4; hex 8000000d; asc     ;;

根据上面锁的详情可以看出来,其加锁情况为:
(-∞,1],(1,3],(3,5],(5,7]
锁住(5,7]是因为,在RR隔离级别下,<=5将从表的第一条记录(a=1)开始比对,一直到出现第一个大于记录5(a=7)为止。

6. RR隔离级别下,查询列是二级唯一索引

select * from t3 where b =5 for update;
会加两个record lock(lock_mode X locks rec but not gap):二级索引(b=5)和二级索引对应的聚集索引(a=3)上加锁,具体如下:

---TRANSACTION 4368, ACTIVE 39 sec
3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 84 localhost root
TABLE LOCK table `test`.`t3` trx id 4368 lock mode IX
RECORD LOCKS space id 39 page no 4 n bits 72 index b of table `test`.`t3` trx id 4368 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 80000005; asc     ;;
 1: len 4; hex 80000003; asc     ;;

RECORD LOCKS space id 39 page no 3 n bits 72 index PRIMARY of table `test`.`t3` trx id 4368 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 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;

select * from t3 where b <=5 for update;
该情况会加5把锁,3把next-key lock,锁住区间(-∞,3],(3,5],(5,7]。2把record lock,锁住的是b=3对应的主键(a=1)和b=5对应的主键a=3。具体如下:

---TRANSACTION 4369, ACTIVE 6 sec
3 lock struct(s), heap size 1136, 5 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 90 localhost root
TABLE LOCK table `test`.`t3` trx id 4369 lock mode IX
RECORD LOCKS space id 39 page no 4 n bits 72 index b of table `test`.`t3` trx id 4369 lock_mode X
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 4; hex 80000001; asc     ;;

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 80000003; 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 80000005; asc     ;;

RECORD LOCKS space id 39 page no 3 n bits 72 index PRIMARY of table `test`.`t3` trx id 4369 lock_mode X locks rec but not gap
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 000000000f70; asc      p;;
 2: len 7; hex cc000001570110; asc     W  ;;
 3: len 4; hex 80000003; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000007; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;
7. RR隔离级别下,查询列是二级非唯一索引

select * from t3 where c =7 for update;
该情况会上3把锁,c=7对应的主键索引a=3上一把record lock,c的取值范围(5,7]之间上一把next-key lock,c的取值范围(7,9)之间上一把gap lock,具体如下

---TRANSACTION 4370, ACTIVE 5 sec
4 lock struct(s), heap size 1136, 3 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 94 localhost root
TABLE LOCK table `test`.`t3` trx id 4370 lock mode IX
RECORD LOCKS space id 39 page no 5 n bits 72 index c of table `test`.`t3` trx id 4370 lock_mode X
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000007; asc     ;;
 1: len 4; hex 80000003; asc     ;;

RECORD LOCKS space id 39 page no 3 n bits 72 index PRIMARY of table `test`.`t3` trx id 4370 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 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;

RECORD LOCKS space id 39 page no 5 n bits 72 index c of table `test`.`t3` trx id 4370 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 80000009; asc     ;;
 1: len 4; hex 80000005; asc     ;;

select * from t3 where c <=7 for update;
该情况上5把锁,3把next-key lock c的取值范围(-∞,5],(5,7],(7,9];2把record lock,对应c=5主键a=1时的记录和c=7主键a=3的记录。具体如下:

---TRANSACTION 4371, ACTIVE 5 sec
3 lock struct(s), heap size 1136, 5 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 98 localhost root
TABLE LOCK table `test`.`t3` trx id 4371 lock mode IX
RECORD LOCKS space id 39 page no 5 n bits 72 index c of table `test`.`t3` trx id 4371 lock_mode X
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 4; hex 80000001; asc     ;;

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

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

RECORD LOCKS space id 39 page no 3 n bits 72 index PRIMARY of table `test`.`t3` trx id 4371 lock_mode X locks rec but not gap
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 000000000f70; asc      p;;
 2: len 7; hex cc000001570110; asc     W  ;;
 3: len 4; hex 80000003; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000007; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;

8. RR隔离级别下,查询列上没有索引

select * from t3 where d =9 for update;
该情况下,由于没有索引,所以其next-key lock的锁住范围(d的取值)为:(-∞,7],(7,9],(9,11],(11,13],(13,+∞] 相当于锁住了整张表

---TRANSACTION 4386, ACTIVE 10 sec
2 lock struct(s), heap size 1136, 5 row lock(s)
MySQL thread id 2, OS thread handle 140018686076672, query id 125 localhost root
TABLE LOCK table `test`.`t3` trx id 4386 lock mode IX
RECORD LOCKS space id 39 page no 3 n bits 80 index PRIMARY of table `test`.`t3` trx id 4386 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 000000000f70; asc      p;;
 2: len 7; hex cc000001570110; asc     W  ;;
 3: len 4; hex 80000003; asc     ;;
 4: len 4; hex 80000005; asc     ;;
 5: len 4; hex 80000007; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 6; hex 000000000f70; asc      p;;
 2: len 7; hex cc00000157011c; asc     W  ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000007; asc     ;;
 5: len 4; hex 80000009; asc     ;;

Record lock, heap no 4 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 000000000f75; asc      u;;
 2: len 7; hex cf0000015a0110; asc     Z  ;;
 3: len 4; hex 80000007; asc     ;;
 4: len 4; hex 80000009; asc     ;;
 5: len 4; hex 8000000b; asc     ;;

Record lock, heap no 5 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 4; hex 80000007; asc     ;;
 1: len 6; hex 000000000f75; asc      u;;
 2: len 7; hex cf0000015a011c; asc     Z  ;;
 3: len 4; hex 80000009; asc     ;;
 4: len 4; hex 8000000b; asc     ;;
 5: len 4; hex 8000000d; asc     ;;

这里有一个明显不一样的是:

Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

supremum 值得是页里面的最后一条记录(伪记录,通过select查不到的,并不是真实的记录),heap no=1 , Infimum 表示的是页里面的第一个记录(伪记录)

可以简单的认为:
supremum 为upper bounds,正去穷大
Infimum 为Minimal bounds,负无穷大
select * from t3 where d <=9 for update;和等值查询情况一样。

二级索引锁住的范围

二级索引锁住的不仅仅是二级索引的Key本身,还有对应的value,也就是主键。
假如某条语句产生以下锁定情况
(1, 3], (3, 6)以及主键索引只锁住了a=5的这条记录 [5, 5]
那么会有以下情况

《MySQL中的锁3-行锁的实现》

参考
MySQL 加锁处理分析
《MySQL技术内幕:InnoDB存储引擎》.[姜承尧]

    原文作者:Coding小聪
    原文地址: https://www.jianshu.com/p/f0a171f4480f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞