InnoDB中锁的算法(2)
Ⅰ、上节回顾
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)的更多相关文章
- InnoDB中锁的算法(1)
Ⅰ.InnoDB锁算法的介绍 首先明确一点,锁锁住的是什么?锁锁住的是索引 Record Lock 单个行记录上的锁 Gap Lock 锁定一个范围,但不包含记录本身 Next-key Lock Ga ...
- InnoDB中锁的算法(3)
Ⅰ.隐式锁vs显示锁 session1: (root@localhost) [test]> show variables like 'tx_isolation'; +-------------- ...
- InnoDB中锁的模式,锁的查看,算法
InnoDB中锁的模式 Ⅰ.总览 S行级共享锁lock in share mode X行级排它锁增删改 IS意向共享锁 IX意向排他锁 AI自增锁 Ⅱ.锁之间的兼容性 兼 X IX S IS X ...
- InnoDB中锁的查看
Ⅰ. show engine innodb status\G 1.1 实力分析一波 锁介绍的那篇中已经提到了这个命令,现在我们开一个参数,更细致的分析一下这个命令 (root@localhost) [ ...
- InnoDB中锁的模式
Ⅰ.总览 S行级共享锁 lock in share mode X行级排它锁 增删改 IS意向共享锁 IX意向排他锁 AI自增锁 Ⅱ.锁之间的兼容性 兼 X IX S IS X × × × × IX × ...
- InnoDB之锁机制
前两天听了姜老大关于InnoDB中锁的相关培训,刚好也在看这方面的知识,就顺便利用时间把这部分知识做个整理,方便自己理解.主要分为下面几个部分 1. InnoDB同步机制 InnoDB存储引擎有两种同 ...
- Innodb中怎么查看锁信息
一.前言 上一篇说了下innodb中锁的大概意思, 这篇说说怎么查看加的哪些锁.不然后续出现死锁或者锁等待都不知道为什么. 二.底层基础表信息 在学会如何查看有哪些锁信息时, 需要了解一些基础表信息, ...
- Innodb中的事务隔离级别和锁的关系
前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力. ...
- Innodb中的事务隔离级别和锁的关系(转)
原文:http://tech.meituan.com/innodb-lock.html 前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库 ...
随机推荐
- maven scope使用和理解
在Maven的依赖管理中,经常会用到依赖的scope设置.这里整理下各种scope的使用场景和说明,以及在使用中的实践心得. scope的使用场景和说明 1.compile 编译范围,默认scope, ...
- php获取客户端IP地址的方法
参考:https://www.cnblogs.com/rendd/p/6183094.html <?php function getip() { //strcasecmp 比较两个字符,不区分大 ...
- 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 ...
- 深入分析 ThreadLocal
ThreadLoacal是什么? ThreadLocal是啥?以前面试别人时就喜欢问这个,有些伙伴喜欢把它和线程同步机制混为一谈,事实上ThreadLocal与线程同步无关.ThreadLocal虽然 ...
- pilicat-dfs 霹雳猫-分布式文件系统
pilicat-dfs 霹雳猫-分布式文件系统 一种可以将网站图片或上传的文件,进行分布式存放的服务,可自动复制到多台物理机器,可满足高可用和负载均衡 已编译好的程序包 http://git.osch ...
- C# 参数签名字符串按 ASCII码排序,注意其中的坑
参数签名中通常是按键值对中键名称的ASCII按从小到大的顺序排序后进行hash为签名字符串.不要直接使用 SortedDictionary<string, string> 有坑的,他是按数 ...
- oracle sql语句实现累加、累减、累乘、累除
在oracle开发过程中经常会遇到累加.减.乘.除的问题.下面对这个做个小的总结 ---创建测试表 CREATE TABLE TEST( PARENT_ID NUMBER, PART_ID NUMBE ...
- LiveSwitch白皮书
https://www.frozenmountain.com/media/1224/frozen-mountain-software-liveswitch-white-paper.pdf —————— ...
- MATLAB 显示输出数据的三种方式
MATLAB 显示输出数据的三种方式 ,转载 https://blog.csdn.net/qq_35318838/article/details/78780412 1.改变数据格式 当数据重复再命令行 ...
- Goland常用快捷键
文件相关快捷键: CTRL+E,打开最近浏览过的文件. CTRL+SHIFT+E,打开最近更改的文件. CTRL+N,可以快速打开struct结构体. CTRL+SHIFT+N,可以快速打开文件. 代 ...