读5.7官网文档之14.7.3 Locks Set by Dif

2020-05-30  本文已影响0人  a50426d44eac

并非翻译,是看了官网文档以后的读书笔记,如有错误,欢迎大家指出。

insert加的锁

insert会分两步加锁,先加一个insert intention lock,第二步会在插入行上面添加一个排他锁。如果插入的行上已经有了排他锁,导致获取不到排他锁就会转成请求插入行的share锁,继续等待。如果获取到share锁,再升级为排他锁。接下来来验证下是不是这样的。

实验相关背景条件

root@localhost>select @@version,@@transaction_isolation from dual;
+------------+-------------------------+
| @@version  | @@transaction_isolation |
+------------+-------------------------+
| 5.7.22-log | REPEATABLE-READ         |
+------------+-------------------------+

root@localhost [(none)] 14:49:58>show create table test.t;
+-------+-------------------------------------------------+
| Table | Create Table                                    |
+-------+-------------------------------------------------+
| t     | CREATE TABLE `t` (
  `a` int(11) NOT NULL,
  `b` int(11) DEFAULT NULL,
  PRIMARY KEY (`a`),
  KEY `idx_b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+-------------------------------------------------+
root@localhost>begin;
Query OK, 0 rows affected (0.00 sec)
root@localhost>insert into t() values(5,6);
Query OK, 1 row affected (0.01 sec)

在看show engine innodb status

---TRANSACTION 1551519, ACTIVE 47 sec
1 lock struct(s), heap size 1136, 0 row lock(s), undo log entries 1
MySQL thread id 24771, OS thread handle 140374083041024, query id 12402642 localhost root
TABLE LOCK table `test`.`t` trx id 1551519 lock mode IX

上面的语句根本看不到插入意向锁和行的排他锁,只能看到一个表级别的意向锁。

既然看不到,就堵塞你,看看能不能看到。

先生成一个gap锁。

###会话一
root@localhost>begin;
Query OK, 0 rows affected (0.00 sec)

root@localhost>select * from t;
+----+------+
| a  | b    |
+----+------+
|  1 |    2 |
|  2 |    3 |
|  3 |    4 |
|  4 |    5 |
| 11 |   22 |
+----+------+
5 rows in set (0.01 sec)
root@localhost>update t set b = 10 where a = 5;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0

在看show engine innodb status日志

2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 24771, OS thread handle 140374083041024, query id 12409482 localhost root
Trx read view will not see trx with id >= 1551536, sees < 1551536
TABLE LOCK table `test`.`t` trx id 1551536 lock mode IX
RECORD LOCKS space id 1483 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 1551536 lock_mode X locks gap before rec. 
###上面一行显示在主键的某条记录前面加上了一个排他的gap锁
###下面这个告知了具体是哪一行
Record lock, heap no 5 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 8000000b; asc     ;;  ###获取hex值的后面四位,然后转换为10进制,可以得到值是11,也就是说把主键值为11前面的gap锁住了。这里多谢叶金荣老师
 1: len 6; hex 00000017a692; asc       ;;
 2: len 7; hex fe0000003b0137; asc     ; 7;;
 3: len 4; hex 80000016; asc     ;;

然后我们再执行insert语句,照理来说insert语句会因为可重复读被堵住。

###会话二
root@localhost [test] 15:18:38>begin;
Query OK, 0 rows affected (0.00 sec)

root@localhost [test] 15:18:40>insert into t() values(5,6);

会话二如愿被阻塞了,再来看一下具体什么锁在等待

---TRANSACTION 1551603, ACTIVE 58 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 24777, OS thread handle 140374067091200, query id 12416225 localhost root update
insert into t() values(5,6)
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1483 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 1551603 lock_mode X locks gap before rec insert intention waiting
##下面这行具体是指主键值是11的行,也就是说是在请求11和4之间的insert intention gap锁
Record lock, heap no 5 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 8000000b; asc     ;;##表示主键值是11的行记录,把hex值的后四位即000b转换为10进制可得值为11
 1: len 6; hex 00000017a692; asc       ;;
 2: len 7; hex fe0000003b0137; asc     ; 7;;
 3: len 4; hex 80000016; asc     ;;

我把会话一提交了,照理来说会话二应该接下来持有的是被插入行也就是(5,6)这一行的排他锁,但是从innodb status当中没有看到,还是只能看到插入意向锁。

既然看不到行的排他锁,只能在试试看别的方法了

###会话一
root@localhost >begin;
Query OK, 0 rows affected (0.00 sec)
root@localhost >insert into t() values(5,6);
###会话二
root@localhost >begin;
Query OK, 0 rows affected (0.00 sec)
root@localhost>insert into t() values(5,6);

同时在两个会话当中插入同一行数据。再来看看锁的等待情况。由于会话一没有提交,所以会话二是不会马上报重复值的错的,而是被阻塞住。

---TRANSACTION 1551610, ACTIVE 3 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 24771, OS thread handle 140374083041024, query id 12425387 localhost root update
insert into t() values(5,6)
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:
##下面这个表示正在等待主键值为5的这一行的
RECORD LOCKS space id 1483 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 1551610 lock mode S waiting
Record lock, heap no 8 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 00000017acf3; asc       ;;
 2: len 7; hex f10000003a0110; asc     :  ;;
 3: len 4; hex 80000006; asc     ;;

---TRANSACTION 1551603, ACTIVE 1001 sec
3 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 1
MySQL thread id 24777, OS thread handle 140374067091200, query id 12419372 localhost root
TABLE LOCK table `test`.`t` trx id 1551603 lock mode IX
RECORD LOCKS space id 1483 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 1551603 lock_mode X locks gap before rec insert intention
##这里还是显示11之前的gap被插入意向锁占着呢
Record lock, heap no 5 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 8000000b; asc     ;;
 1: len 6; hex 00000017a692; asc       ;;
 2: len 7; hex fe0000003b0137; asc     ; 7;;
 3: len 4; hex 80000016; asc     ;;
##下面表示主键值为5的这一行被加上了排他锁
RECORD LOCKS space id 1483 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 1551603 lock_mode X locks rec but not gap
Record lock, heap no 8 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;; #这里的hex值0005转换为10进制就是5
 1: len 6; hex 00000017acf3; asc       ;;
 2: len 7; hex f10000003a0110; asc     :  ;;
 3: len 4; hex 80000006; asc     ;;

上面的日志中可以看到会话一在被插入行上加了排他锁,会话二由于插入的重复数据,所以变成了请求插入上的行共享锁,和文档描述一致。

总结

通过三个实验,终于看到官网文档所描述的锁了,先尝试加插入意向锁,再加上行的排他锁,如果行已经被加上了排他锁,会变成请求行共享锁继续等待。不过要吐槽的还是这个锁的查看机制,只能通过show engine innodb status才能看的清楚。要是通过表的话,感觉会方便好多。

上一篇下一篇

猜你喜欢

热点阅读