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 前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库 ...
随机推荐
- R语言学习-set.seed()
今天查了一下R语言中set.seed(),该命令的作用是设定生成随机数的种子,种子是为了让结果具有重复性.如果不设定种子,生成的随机数无法重现. > x<-rnorm(10) #随机生成1 ...
- 分析轮子(五)- Vector.java
注:玩的是JDK1.7版本 一: 先上类图,从类图上看和 ArrayList.java 非常相像,可查看 分析轮子(一)-ArrayList.java 二:然后看源码,发现和 ArrayList.ja ...
- 爬虫对自己服务器 CPU,内存和网速的影响
今天无事写一遍关于爬虫对计算机的影响,主要是给小白同学普及一下爬虫的基础知识. 在我们写爬虫的时候,首先会想到开多线程,如果使用的语言是Python,很不幸,因为Python存在 GIL,在任何时候 ...
- CSS 水平居中与垂直居中
前言 在CSS布局中,水平居中与垂直居中一直是用到比较多的,在本篇中将介绍水平居中.垂直居中的几种方式. 示例 HTML: <div class="parent"> & ...
- Android 提高 gradle 的编译速度
随着项目在国内各个商店上线,开始介入了渠道的概念. 目前总共有 13 家商店,尝试使用 ./gradlew assembleRelease 命令打包,耗时将近 40 分钟. 因此搜索了一些可以提供编译 ...
- “The subscription does not exist” when a distributor primary replica fails over to a replica that does not use the same agent profile
Symptoms Consider the following scenario: In Microsoft SQL Server 2017, you have a distribution agen ...
- csproj文件中copy指令的使用方式
实际开发中有很多项目需要引用第三方的dll或者资源文件,且文件比较多,在运行时这些文件需要被拷贝到BIN目录. 使用VS自带的"复制到输出目录",似然方便,但是比较不零活,经过多次 ...
- 浏览器神器--vimium
自从学会了正确的坐姿,坐在电脑一整天腰也不酸了.背也不痛了,精神倍棒吃嘛嘛香 zuomeng.png 但奈何使用鼠标久了,手腕.肩膀依旧疼痛.偶尔逛知乎,看到有人推荐chrome浏览器的vimiu ...
- [转]Jsoup(一)Jsoup详解(官方)
原文地址:http://www.cnblogs.com/zhangyinhua/p/8037599.html 一.Jsoup概述 1.1.简介 jsoup 是一款Java 的HTML解析器,可 ...
- 分布式任务&分布式锁
目前系统中存在批量审批.批量授权等各个操作,批量操作中可能因为处理机器.线程不同,造成刷新缓存丢失授权等信息,如批量审批同一用户权限多个权限申请后,流程平台并发的发送多个http请求到acl不同服务器 ...