Ⅰ、上节回顾

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. (原)visual studio 2015中添加dll路径

    转载请注明出处: https://www.cnblogs.com/darkknightzh/p/9922033.html 使用vs2015调用opencv 3.4时,除了需要在“VC++目录”中”包含 ...

  2. iOS--App功耗优化

    良好的用户体验需要如下要素: 电池寿命长.随着能效降低,电池寿命也会降低.但用户想让自己的移动设备全天候待命. 速度快.iOS系统处理复杂操作时仍能提供很好的性能. 响应快.同一时刻消耗太多资源会使U ...

  3. 分析轮子(九)- Cloneable.java

    注:玩的是JDK1.7版本 一:Cloneable.java 接口也是标记接口,所以,它没有任何方法和属性,实现此接口表示的意思是:可以调用 Object.java 类的 clone() 方法,进行简 ...

  4. 减少网站跳转时间,增强网站数据安全——HSTS 详解

    近年来随着 Google.Apple.百度等公司不断推动 HTTPS 普及,全网 HTTPS 已是大势所趋.目前多数网站都已经支持 HTTPS 访问,但是在由 HTTP 转向 HTTPS 路程中,不少 ...

  5. Linux进程资源占用分析

    [时间:2018-03] [状态:Open] [关键词:linux, 进程,proc,top] 0 引言 最近在分析安卓程序上的monkey测试日志时发现,需要了解下Linux进程资源占用情况及其查看 ...

  6. 【转】Mac OS X 上修改主机名

    修改主机名称 sudo scutil --set HostName MacBookPro 修改共享名称 sudo scutil --set ComputerName MacBookPro [转自]:h ...

  7. Win10添加右键在此处打开命令行

    通过添加注册表项,实现右击“在此处打开命令行功能” 注册表位置:HKEY_CLASSES_ROOT\Directory\Background\shell\ win10系统用标识右键菜单打开命令行的键, ...

  8. 【iCore4 双核心板_uC/OS-II】例程三:任务的挂起与恢复

    一.实验说明: 当一个任务正在运行的时候,由于某种情况可能需要终止运行一段时间,终止的这段时间就是 所谓的任务的挂起,可以由该任务自身或者其他任务来挂起一个任务.当被挂起的任务需要再次运 行的时候,可 ...

  9. hdoj:2055

    #include <iostream> #include <string> using namespace std; bool islower(char ch) { if (c ...

  10. Linux服务器重启后MySQL启动失败

    Redirecting to /bin/systemctl start  mysql.service Job for mysqld.service failed because the control ...