Ⅰ、上节回顾

session1:

(root@localhost) [test]> select * from l;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 2 | 4 | 6 | 8 |
| 4 | 6 | 8 | 10 |
| 6 | 8 | 10 | 12 |
| 8 | 10 | 12 | 14 |
+---+------+------+------+
4 rows in set (0.00 sec) (root@localhost) [test]> show variables like 'tx_isolation';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.01 sec) (root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> select * from l where b = 6 for update;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 4 | 6 | 8 | 10 |
+---+------+------+------+
1 row in set (0.09 sec) pk 2 4 6 8
key 4 6 8 10
二级索引锁住的是(4,6]&&(6,8)
主键锁住的是4

session2:

(root@localhost) [(test)]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> insert into l values (3,4,14,20); hang~~~

session1:

(root@localhost) [(none)]> show engine innodb status\G
...
MySQL thread id 1087, OS thread handle 139830446065408, query id 7300 localhost root update
insert into l values (3,4,14,20)
------- TRX HAS BEEN WAITING 19 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1358 page no 5 n bits 72 index b of table `test`.`l` trx id 31220594 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 4; hex 80000006; asc ;;
1: len 4; hex 80000004; asc ;;
...
4在被锁住的范围之内,所以插不进去

那(1,4,14,20)能插入吗?先公布答案,是可以插入的

为什么?

这里有一个隐晦的问题

二级索引排序的时候包含主键值排序,锁的时候范围也是包含主键值,如下:

((4,2),(6,4)],((6,4),(8,6))

(4,3)在这个范围内,所以不能插,而(4,1)不在这范围内,可以插

insert (5,4,14,20)也会阻塞,(4,5)在范围中

Ⅱ、走索引查询的记录不存在

2.1 rr事务隔离级别

(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> select * from l where b = 12 for update;
Empty set (0.00 sec) (root@localhost) [test]> show engine innodb status\G
...
---TRANSACTION 31220600, ACTIVE 7 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 1104, OS thread handle 139830452774656, query id 7383 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`l` trx id 31220600 lock mode IX
RECORD LOCKS space id 1358 page no 5 n bits 72 index b of table `test`.`l` trx id 31220600 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;;
...
heap no 1 0和1的heap no表示的是min和max的记录,虚拟的
n_fields 1 只有一个列,伪列
key min 4 6 8 10 max

在max上加了锁,范围为(10,正无穷),意味着插入任意大于10的记录都是不可以的

rr级别时,如果搜索一条记录搜不到,就会在max上加锁,意味着这条没查到的记录之后的范围都插不了

为什么呢?

如果第一次读12没有读到不把10往后的都锁住,那一个线程插入了12这条记录,第二次再去读就会读到12,就发生了幻读

再来

session1:

(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> select * from l where b = 7 for update;
Empty set (0.00 sec) (root@localhost) [test]> show engine innodb status\G
···
---TRANSACTION 31220601, ACTIVE 51 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 1104, OS thread handle 139830452774656, query id 7387 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`l` trx id 31220601 lock mode IX
RECORD LOCKS space id 1358 page no 5 n bits 72 index b of table `test`.`l` trx id 31220601 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 80000006; asc ;;
···
在8上面加了一个gap锁,8本身是不锁的

session2:

(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> select * from l where b = 8 for update;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 6 | 8 | 10 | 12 |
+---+------+------+------+
1 row in set (0.00 sec)
这时候8这条记录上又有了Next-key Lock锁,锁住6到8,8本身也被锁住,8上面两把锁是不抵触的

2.2 rc事务隔离级别

(root@localhost) [test]> show variables like 'tx_isolation';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.00 sec) (root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> select * from l where b = 12 for update;
Empty set (0.00 sec) (root@localhost) [test]> show engine innodb status\G
...
------------
TRANSACTIONS
------------
Trx id counter 31220604
Purge done for trx's n:o < 31220593 undo n:o < 0 state: running but idle
History list length 35
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421305875783280, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421305875781456, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 31220603, ACTIVE 6 sec
1 lock struct(s), heap size 1136, 0 row lock(s)
MySQL thread id 1106, OS thread handle 139830446065408, query id 7436 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`l` trx id 31220603 lock mode IX
...

会发现并没有锁,读到没有12这条记录,直接就释放了,rc不解决幻读,这么看rc的insert并发性能会更好

Ⅲ、不走索引的情况怎么锁?

3.1 rc事务隔离级别

(root@localhost) [test]> show variables like 'tx_isolation';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.01 sec) (root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> select * from l where d = 10 for update;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 4 | 6 | 8 | 10 |
+---+------+------+------+
1 row in set (0.00 sec) (root@localhost) [test]> show engine innodb status\G
...
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421305875783280, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421305875781456, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 31220604, ACTIVE 11 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 1106, OS thread handle 139830446065408, query id 7446 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`l` trx id 31220604 lock mode IX
RECORD LOCKS space id 1358 page no 3 n bits 72 index PRIMARY of table `test`.`l` trx id 31220604 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 80000004; asc ;;
1: len 6; hex 000001c1b93a; asc :;;
2: len 7; hex e1000001a90110; asc ;;
3: len 4; hex 80000006; asc ;;
4: len 4; hex 80000008; asc ;;
5: len 4; hex 8000000a; asc ;;
...

会产生一个记录锁,对d=10这条记录对应的主键加锁

3.2 rr事务隔离级别

(root@localhost) [test]> show variables like 'tx_isolation';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec) (root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> select * from l where d = 10 for update;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 4 | 6 | 8 | 10 |
+---+------+------+------+
1 row in set (0.00 sec) (root@localhost) [test]> show engine innodb status\G
...
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421305875783280, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421305875781456, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 31220606, ACTIVE 22 sec
2 lock struct(s), heap size 1136, 5 row lock(s)
MySQL thread id 1106, OS thread handle 139830446065408, query id 7459 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`l` trx id 31220606 lock mode IX
RECORD LOCKS space id 1358 page no 3 n bits 72 index PRIMARY of table `test`.`l` trx id 31220606 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 80000002; asc ;;
1: len 6; hex 000001c1b939; asc 9;;
2: len 7; hex e0000001a80110; asc ;;
3: len 4; hex 80000004; asc ;;
4: len 4; hex 80000006; asc ;;
5: len 4; hex 80000008; asc ;; Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 4; hex 80000004; asc ;;
1: len 6; hex 000001c1b93a; asc :;;
2: len 7; hex e1000001a90110; asc ;;
3: len 4; hex 80000006; asc ;;
4: len 4; hex 80000008; asc ;;
5: len 4; hex 8000000a; asc ;; Record lock, heap no 4 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 4; hex 80000006; asc ;;
1: len 6; hex 000001c1b93f; asc ?;;
2: len 7; hex e40000015d0110; asc ] ;;
3: len 4; hex 80000008; asc ;;
4: len 4; hex 8000000a; asc ;;
5: len 4; hex 8000000c; asc ;; Record lock, heap no 5 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 4; hex 80000008; asc ;;
1: len 6; hex 000001c1b940; asc @;;
2: len 7; hex e50000015f0110; asc _ ;;
3: len 4; hex 8000000a; asc ;;
4: len 4; hex 8000000c; asc ;;
5: len 4; hex 8000000e; asc ;;
...

Next-key Lock锁住了主键的2,4,6,8

(负无穷,2],(2,4],(4,6],(6,8],(8,正无穷)

这并不是表锁(没有表升级),只是表现形式类似整个锁住,如果表有100w记录,会产生100w个lock,锁模式是Next-key Locking,任何记录的插入和更新都是不可以的,锁的代价很大

因为后面插入任何一条记录都可以是d=10,所以任何一条记录都要被锁住,随便插一个d=10的记录都给插那就乱套了,又幻读了,那就不允许任何记录插入吧

tips:

rr本身不解决幻读,只有在序列化的事务隔离级别之下才解决幻读,但是MySQL的锁比较特殊,在rr隔离级别下就解决幻读

InnoDB中锁的算法(2)的更多相关文章

  1. InnoDB中锁的算法(1)

    Ⅰ.InnoDB锁算法的介绍 首先明确一点,锁锁住的是什么?锁锁住的是索引 Record Lock 单个行记录上的锁 Gap Lock 锁定一个范围,但不包含记录本身 Next-key Lock Ga ...

  2. InnoDB中锁的算法(3)

    Ⅰ.隐式锁vs显示锁 session1: (root@localhost) [test]> show variables like 'tx_isolation'; +-------------- ...

  3. InnoDB中锁的模式,锁的查看,算法

    InnoDB中锁的模式   Ⅰ.总览 S行级共享锁lock in share mode X行级排它锁增删改 IS意向共享锁 IX意向排他锁 AI自增锁 Ⅱ.锁之间的兼容性 兼 X IX S IS X ...

  4. InnoDB中锁的查看

    Ⅰ. show engine innodb status\G 1.1 实力分析一波 锁介绍的那篇中已经提到了这个命令,现在我们开一个参数,更细致的分析一下这个命令 (root@localhost) [ ...

  5. InnoDB中锁的模式

    Ⅰ.总览 S行级共享锁 lock in share mode X行级排它锁 增删改 IS意向共享锁 IX意向排他锁 AI自增锁 Ⅱ.锁之间的兼容性 兼 X IX S IS X × × × × IX × ...

  6. InnoDB之锁机制

    前两天听了姜老大关于InnoDB中锁的相关培训,刚好也在看这方面的知识,就顺便利用时间把这部分知识做个整理,方便自己理解.主要分为下面几个部分 1. InnoDB同步机制 InnoDB存储引擎有两种同 ...

  7. Innodb中怎么查看锁信息

    一.前言 上一篇说了下innodb中锁的大概意思, 这篇说说怎么查看加的哪些锁.不然后续出现死锁或者锁等待都不知道为什么. 二.底层基础表信息 在学会如何查看有哪些锁信息时, 需要了解一些基础表信息, ...

  8. Innodb中的事务隔离级别和锁的关系

    前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力. ...

  9. Innodb中的事务隔离级别和锁的关系(转)

    原文:http://tech.meituan.com/innodb-lock.html 前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库 ...

随机推荐

  1. maven scope使用和理解

    在Maven的依赖管理中,经常会用到依赖的scope设置.这里整理下各种scope的使用场景和说明,以及在使用中的实践心得. scope的使用场景和说明 1.compile 编译范围,默认scope, ...

  2. php获取客户端IP地址的方法

    参考:https://www.cnblogs.com/rendd/p/6183094.html <?php function getip() { //strcasecmp 比较两个字符,不区分大 ...

  3. Atitit s2018.5 s5 doc list on com pc.docx  v2

    Atitit s2018.5 s5  doc list on com pc.docx  Acc  112237553.docx Acc Acc  112237553.docx Acc baidu ne ...

  4. 深入分析 ThreadLocal

    ThreadLoacal是什么? ThreadLocal是啥?以前面试别人时就喜欢问这个,有些伙伴喜欢把它和线程同步机制混为一谈,事实上ThreadLocal与线程同步无关.ThreadLocal虽然 ...

  5. pilicat-dfs 霹雳猫-分布式文件系统

    pilicat-dfs 霹雳猫-分布式文件系统 一种可以将网站图片或上传的文件,进行分布式存放的服务,可自动复制到多台物理机器,可满足高可用和负载均衡 已编译好的程序包 http://git.osch ...

  6. C# 参数签名字符串按 ASCII码排序,注意其中的坑

    参数签名中通常是按键值对中键名称的ASCII按从小到大的顺序排序后进行hash为签名字符串.不要直接使用 SortedDictionary<string, string> 有坑的,他是按数 ...

  7. oracle sql语句实现累加、累减、累乘、累除

    在oracle开发过程中经常会遇到累加.减.乘.除的问题.下面对这个做个小的总结 ---创建测试表 CREATE TABLE TEST( PARENT_ID NUMBER, PART_ID NUMBE ...

  8. LiveSwitch白皮书

    https://www.frozenmountain.com/media/1224/frozen-mountain-software-liveswitch-white-paper.pdf —————— ...

  9. MATLAB 显示输出数据的三种方式

    MATLAB 显示输出数据的三种方式 ,转载 https://blog.csdn.net/qq_35318838/article/details/78780412 1.改变数据格式 当数据重复再命令行 ...

  10. Goland常用快捷键

    文件相关快捷键: CTRL+E,打开最近浏览过的文件. CTRL+SHIFT+E,打开最近更改的文件. CTRL+N,可以快速打开struct结构体. CTRL+SHIFT+N,可以快速打开文件. 代 ...