当前位置:网站首页>Mysql间隙锁
Mysql间隙锁
2022-07-01 12:43:00 【唐伯虎点蚊香dw】
学习Mysql, 总会有一座绕不过去的大山, 那就是锁。理论上,锁的花样再多,也超不出操作系统课上讲的那些范畴,但是Mysql锁让我翻车了。
在Mysql中锁的粒度可分为:表级锁,行级锁,间隙锁 三种。表级锁和行级锁都没什么太难理解的地方。只有间隙锁我无法准确理解其设计意图,而且我试验下来的现象让我觉得很诡异。
那么为什么会有间隙锁这种东西呢,按大部分能查到的资料表示,间隙锁的引入是为了解决在RR隔离级别的幻读问题。
下面来看一个实例,首先创建一个Table:
Create Table: CREATE TABLE `foo` (
`uid` int(11) NOT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`uid`),
KEY `age` (`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into foo values(1,1),(4,4),(7,7),(9,9);
然后,开两个mysql客户端(M1,M2),其执行顺序如下:
M1: begin;
M1: select * from foo were uid > 1 and uid < 5 for update;
M2: begin;insert into foo values(2,2);commit;
M1: select * from foo were uid > 1 and uid < 5 for update;
M1: commit;
如果在M1第一次执行select语句时只加行锁,那么锁住的就只有uid=4这一行。 在M1第二次执行select语句时,由于M2插入了一条(2,2), 因此会多查询出一条(2,2)的记录。 这就会产生幻读。
mysql的解决方案是:使用间隙锁,将uid在间隙区间(1,4),(4,7)的全部加锁,这样当M2在insert行数据(2,2)甚至(6,6)会被锁阻塞以防止M1出现幻读。
如果事情到这里完美结束,那我也不会翻车了,再看另外三条sql语句:
M1: begin;
M1: select * from foo were age = 4 for update;
M2: begin;insert into foo values(6,6);commit;
M1: select * from foo were age = 4 for update;
M1: commit;
手动执行一下就会发现M2会被锁阻塞住,这是因为他对age加了间隙锁(锁是加在索引上的)。
由于锁是加在索引上的, 按照我第一反应,直接对age=4这一条索引加锁就解决问题了,为什么要加间隙锁?
我查了很久,才找到一个很少有人提到但很重要的点二级索引中存储的主键,会参于二级索引排序,比如age索引进行排序时,实际用的是(age,uid)来进行排序。而之所以会使用uid参与排序我想大部分原因应该是B+树内不允许存储相同的值。使用age,uid进行拼接之后可以保证所有的二级索引,在B+树中的值一定是惟一的。
换句话说,我们无法单纯的锁住age=4这一条件,因为可能会存在(age,uid)= (4,1)/(4,2)/(4,5)等任意索引。
二级索引在拼接时,由于age在前uid在后,因此age的值在一定程度上就代表了整个索引值。这也是为什么间隙锁可以锁住age=4这一条件。
为了验证上述说法正确性,来看如下sql:
M1: begin;
M1: select * from foo were age = 4 for update;
M2: begin;update foo set age = 2 where uid = 1;commit;
M1: select * from foo were age = 4 for update;
M1: commit;
先简单分析一下 : 1. age是非惟一二级索引 2. 二级索引在内部实现是由age,uid拼接之后才参与排序的 3. 间隙锁住了(age,uid) = (1,1) ~ (4,4)的开区间 4. M2执行的语句是想插入一个二级索引值(2,1)
根据间隙锁原理,我们可以推段出M2会被间隙锁给阻塞住,而事实也正是这样。
ps. 二级索引中存储的主键会参于二级索引排序,这一点我认为非常重要。不知道为什么很多参考书都有意无意略过去了。
------------------------------------------------------------------------------------------------------------------------------
总结:
Mysql MVCC解决了RR事务的可重复读问题,使用间隙锁解决了RR级别的幻读问题
Mysql的间隙锁是为了在RR级别解决幻读问题而引入的,间隙锁是gap lock ,而mysql 用的是间隙锁和gap锁的结合,也就是next-key lock,而在不同的索引上,mysql加锁的方式也不一样:
唯一索引上:如果条件为=5 ,间隙锁退化为行锁,也就是只会锁住条件中的那一行对象,如果是>5,则会添加一个[5, ∞) 的一个next-key锁,5这个行锁和(5,∞)这个间隙锁
普通索引上:如果条件为5,那么mysql会通过5查询左右两边的一个间隙,也就是比5小的第一个值和比5大的第一个值,然后加一个间隙锁,比如数据库还有两条数据的索引值为 3 和 7,那么mysql会加一个(3-5)[5](5-7]的这么一个间隙锁,为什么普通索引需要这么加,那是因为普通索引是可以重复的,这里引入之前的一句话
二级索引中存储的主键,会参于二级索引排序,比如age索引进行排序时,实际用的是(age,uid)来进行排序。而之所以会使用uid参与排序我想大部分原因应该是B+树内不允许存储相同的值。使用age,uid进行拼接之后可以保证所有的二级索引,在B+树中的值一定是惟一的。
换句话说,我们无法单纯的锁住age=4这一条件,因为可能会存在(age,uid)= (4,1)/(4,2)/(4,5)等任意索引。
二级索引在拼接时,由于age在前uid在后,因此age的值在一定程度上就代表了整个索引值。这也是为什么间隙锁可以锁住age=4这一条件。
间隙锁是一个左开右闭的一个区间,比如上面的例子,等值查询的时候 where c = 5,那么会加一个(3,7]的一个左开右闭间隙锁,如果我们插入c=3的一条记录是不会阻塞的,但是如果我们插入一条c=7的记录,那是会阻塞的
无索引:因为mysql的锁都是在索引上,如果没有索引则是使用表锁
边栏推荐
- When Sqlalchemy deletes records with foreign key constraints, the foreign key constraints do not work. What is the solution?
- 题目 1004: 母牛的故事(递推)
- 6.30模拟赛总结
- Wang Xing's infinite game ushers in the "ultimate" battle
- Share several tools for designing exquisite circuit diagrams
- 运行Powershell脚本提示“因为在此系统上禁止运行脚本”解决办法
- There are still many things to be done in the second half of the year
- 【开发大杀器】之Idea
- leetcode:226. Flip binary tree [DFS flip]
- 有没有大佬 遇到过flink监控postgresql数据库, 检查点无法使用的问题
猜你喜欢

ROS2 Foxy depthai_ ROS tutorial

Sort out relevant contents of ansible

Vs code setting Click to open a new file window without overwriting the previous window
![leetcode:226. Flip binary tree [DFS flip]](/img/b8/6c5596ac30de59f0f347bb0bddf574.png)
leetcode:226. Flip binary tree [DFS flip]

codeforces -- 4B. Before an Exam

Shell script imports stored procedures into the database

ROS2 Foxy depthai_ros教程

华为HMS Core携手超图为三维GIS注入新动能

Chained storage of queues

Manage nodejs with NVM (downgrade the high version to the low version)
随机推荐
Using burpsuite to capture app packages
从数据库中更新一条数据,用cdc会同时获得op字段分别为d和c的两条数据吗?我记得之前是只有op为u
6.30模拟赛总结
Application of stack -- bracket matching problem
Ikvm of toolbox Net project new progress
The difference between memcpy and strcpy
A hole in solder paste
Circular linked list--
Perl 5.10.0 installation package download
List of QT players [easy to understand]
强大、好用、适合程序员/软件开发者的专业编辑器/笔记软件综合评测和全面推荐
R语言基于h2o包构建二分类模型:使用h2o.gbm构建梯度提升机模型GBM、使用h2o.auc计算模型的AUC值
项目部署,一点也不难!
Powerful, easy-to-use, professional editor / notebook software suitable for programmers / software developers, comprehensive evaluation and comprehensive recommendation
codeforces -- 4B. Before an Exam
腾讯黎巍:深耕“监管科技”,护航数字经济行稳致远
Three stages of aho
PG基础篇--逻辑结构管理(触发器)
Need your own cognition
硬阈值(Hard Thresholding)函数解读[通俗易懂]