一文详解 MySQL 中的间隙锁
博客:https://www.emanjusaka.com
博客园:https://www.cnblogs.com/emanjusaka
公众号:emanjusaka的编程栈
by emanjusaka from https://www.emanjusaka.com/archives/mysql-gap-lock 彼岸花开可奈何
本文为原创文章,可能会更新知识点以及修正文中的一些错误,全文转载请保留原文地址,避免产生因未即时修正导致的误导。
间隙锁(Gap Lock)是(RR 级别下)一个在索引记录之间的间隙上的锁,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。
间隙锁是 MySQL 行锁的一种,与行锁不同的是间隙锁可能锁定的是一行数据,也可能锁住一个间隙。
触发条件
事务隔离级别为 REPEATABLE-READ(可重复读),间隙锁是为了防止幻读。
使用范围查询条件
使用等值查询但未命中记录时,如果查询的条件列上有索引
索引不唯一的情况
锁定区间
间隙锁会向左找第一个比当前索引值小的值,向右找第一个比当前索引值大的值(没有则为正无穷),将此区间锁住,从而阻止其他事务在此区间插入数据
间隙锁(Gap Lock),左右都是开区间,间隙锁 + 行锁组合成 Next-key lock,左开右闭区间。
加锁规则
加锁的基本单位是 next-key lock,它是左开右闭区间
查找过程中访问到的对象才会加锁
唯一索引上的等值查询,并且记录存在,next-key lock 退化为行锁
唯一索引上的范围查询会访问到不满足条件的第一个值为止
索引上的等值查询,会将距离最近的左边界和右边界作为锁定范围,如果索引不是唯一索引还会继续向右匹配,直到遇见第一个不满足条件的值,如果最后一个值不等于查询条件,Next-Key Lock 退化为间隙锁。
注意,delete 语句加锁的逻辑,其实跟 select ... for update 是类似的。
这些加锁规则并不全部适应 MySQL 的全部版本,在新版本的 MySQL 中可能会有一些变动,大体上是符合这些规则的。
我们也可以执行select * FROM performance_schema.data_locks;来查看具体加了什么锁。
LOCK_TYPE
TABLE:表锁
RECORD:行级锁
LOCK_MODE
X:next-key 锁
X,REC_NOT_GAP:记录锁
X,GAP:间隙锁
间隙锁的作用
与行锁(例如乐观锁高级实现,MVCC)组合成 Next-key lock,在可重复读这种隔离级别下一起工作避免幻读。
案例演示
环境:MySQL8.3.0,InnoDB引擎, RR 隔离级别
表结构:
CREATE TABLE t (
id int(11) NOT NULL,
c int(11) DEFAULT NULL,
d int(11) DEFAULT NULL,
PRIMARY KEY (id),
KEY c (c)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20);
| id | c | d |
|---|---|---|
| 0 | 0 | 0 |
| 5 | 5 | 5 |
| 10 | 10 | 10 |
| 15 | 15 | 15 |
| 20 | 20 | 20 |
存在的间隙:
(-∞,0]
(0,5]
(5,10]
(10,15]
(15,20]
(20,+supremum]
InnoDB 给每个索引加了一个不存在的最大值 supremum,这样才符合“左开右闭区间”。
唯一索引等值锁定存在的数据
| 时刻 | 事务 1 | 事务 2 |
|---|---|---|
| t1 | begin; select * from t where id = 5 for update; | |
| t2 | begin; insert into t value(4,4,4); --- success | |
| insert into t value(6,6,6); --- success |
根据规则 3,事务 1 中执行的 select 语句,会退化成行锁,只会锁定 5 这一行记录

索引等值锁定
| 时刻 | 事务 1 | 事务 2 |
|---|---|---|
| t1 | begin; select * from t where id = 3 for update; --- 不存在的数据 | |
| t2 | begin; insert into t value(6,6,6); --- success | |
| t3 | insert into t value(4,4,4); --- block |
根据规则 1加锁范围是(0,5],再根据规则 5由于向右遍历最后一个值 5 不满足等值条件退化为间隙锁(0,5)
插入 数据6 不在间隙锁的范围内可以插入成功,而数据 4 是间隙锁锁定范围进入阻塞状态

唯一索引范围锁定
| 时刻 | 事务 1 | 事务 2 |
|---|---|---|
| t1 | begin; select * from t where id >= 5 and id < 6 for update; | |
| t2 | begin; insert into t value(7,7,7); --- block |
这个可以分为两部分看
首先看 id > = 5,锁定区间(0,5]根据规则 1 和规则 3 会退化成行锁
再看 id < 6 根据规则 4 锁定区间为(5,10]
综合两部分最终锁定区间[5,10]
注意:这个锁定区间在不同版本的 MySQL 中可能表现不同,在 8.3.0 版本中第二部分会退化成间隙锁,锁定区间变成了[5,10)

非唯一索引范围锁定
| 时刻 | 事务 1 | 事务 2 | 事务 3 |
|---|---|---|---|
| t1 | begin; select * from t where c >= 10 and c < 11 for update; | ||
| t2 | begin; insert into t values(7,7,7); --block | ||
| t3 | begin; update t set d = d + 1 where c = 15; --block |
用 c =10 定位记录,给索引 c 加上了 next-key lock (5,10],它不会退化成行锁,索引 c 不是唯一索引。因此最终索引 c 上加的(5,10] 和 (10,15]这两个 next-key lock

limit语句加锁
| 时刻 | 事务 1 | 事务 2 |
|---|---|---|
| t1 | begin; select * from t where c = 10 limit 1; | |
| begin; insert into t values(12,12,12); ---success |
如果没有 limit 语句的话在索引 c 上加锁范围是从(c=5,id=5)到 (c =15,id=15)。
但是因为加了 limit 1 的限制,因此在访问(c=10,id=10)这一行时,满足条件的语句已经有1 条了循环结束。
因此索引 c 上的加锁范围就变成了从(c=5,id=5)到(c=10,id=10)。


参考资料
谦学于心,谷纳万物,静思致远,共筑收获之旅!
原文地址: https://www.emanjusaka.com/archives/mysql-gap-lock
一文详解 MySQL 中的间隙锁的更多相关文章
- 详解MySQL中EXPLAIN解释命令
Explain 结果解读与实践 基于 MySQL 5.0.67 ,存储引擎 MyISAM . 注:单独一行的"%%"及"`"表示分隔内容,就象分开“第一 ...
- 一文详解MySQL的锁机制
一.表级锁.行级锁.页级锁 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则. MySQL数据库由于其自身架构的特点,存在多种数据存储引擎, ...
- 详解MySQL中concat函数的用法(连接字符串)
MySQL中concat函数 使用方法: CONCAT(str1,str2,…) 返回结果为连接参数产生的字符串.如有任何一个参数为NULL ,则返回值为 NULL. 注意: 如果所有参数均为非二进制 ...
- 详解 MySQL 中的 explain
来源:persister 链接:http://www.blogjava.net/persister/archive/2008/10/27/236813.html 在 explain的帮助下,您就知道什 ...
- 详解MySQL中EXPLAIN解释命令(转)
explain显示了mysql如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句. 使用方法,在select语句前加上explain就可以了: 如: expla ...
- 一文详解MySQL如何同时自增自减多个字段
本文将带大家聊一下如何同时自增自减多个字段 开始之前,先分享一套MySQL教程,小白入门或者学习巩固都可以看 MySQL基础入门-mysql教程-数据库实战(MySQL基础+MySQL高级+MySQL ...
- 高级程序员必知必会,一文详解MySQL主从同步原理,推荐收藏
1. MySQL主从同步实现方式 MySQL主从同步是基于Bin Log实现的,而Bin Log记录的是原始SQL语句. Bin Log共有三种日志格式,可以binlog_format配置参数指定. ...
- 详解mysql中的Using与On的用法
多用才可以体会各个关键字的用法啊... 原文来自[http://bbs.php100.com/read-htm-tid-148469.html] 在用Join进行多表联合查询时,我们通常使用On来建立 ...
- MySQL数据类型 int(M) 表示什么意思?详解mysql int类型的长度值问题
MySQL 数据类型中的 integer types 有点奇怪.你可能会见到诸如:int(3).int(4).int(8) 之类的 int 数据类型.刚接触 MySQL 的时候,我还以为 int(3) ...
- Mysql常用show命令,show variables like xxx 详解,mysql运行时参数
MySQL中有很多的基本命令,show命令也是其中之一,在很多使用者中对show命令的使用还容易产生混淆,本文汇集了show命令的众多用法. 详细: http://dev.mysql.com/doc/ ...
随机推荐
- Java Class 文件中Method的存储
class文件是java编译后的文件类型.其代表一个类,其有专门的存储格式.其中会存放数据也会存放方法,而所谓的方法存放就是将方法中的调用都转换成java字节码指令.所方法调用从机器的角度看就是对于寄 ...
- Java设计模式——适配器模式的精妙应用:探秘 JDK 源码中的 Set 类
在 Java 编程的世界里,JDK 源码犹如一座神秘的宝藏,其中的 Set 类更是我们日常开发中频繁使用的利器.今天,就让我们像勇敢的探险家一样,深入 JDK 源码,揭开 Set 类的神秘面纱,重点剖 ...
- PDFSharp - Graphics 绘制接口
PDFSharp - Graphics Graphics - PDFsharp and MigraDoc Wiki 所有的 Graphics 类型都设计成模仿来自 System.Drawing 命名空 ...
- 中电金信:数字经济时代,AI+金融技术应用与未来发展
- 中电金信:技术实践|Flink维度表关联方案解析
导语:Flink是一个对有界和无界数据流进行状态计算的分布式处理引擎和框架,主要用来处理流式数据.它既可以处理有界的批量数据集,也可以处理无界的实时流数据,为批处理和流处理提供了统一编程模型. 维 ...
- 2024年1月Java项目开发指南4:IDEA里配置MYSQL
提前声明:文章首发博客园(cnblogs.com/mllt) 自动"搬家"(同步)到CSDN,如果博客园中文章发生修改是不会同步过去的,所以建议大家到我的博客园中查看 前提条件: ...
- 解决:pip is configured with locations that require TLS/SSL
解决: mkdir -p ~/.pipvim ~/.pip/pip.conf然后输入内容: [global]index-url = http://mirrors.aliyun.com/pypi/sim ...
- X-Frame-Options
X-Frame-Options头主要是为了防止站点被别人劫持,iframe引入 nginx配置形式: add_header X-Frame-Options ALLOWALL; #允许所有域名ifram ...
- resttemplate的ReadTimeout和ConnectTimeout
问题描述:今天,在做微服务开发中,A服务区调用B服务,获取数据做导出excel操作.A服务出现了"java.net.SocketTimeoutException: Read timed ou ...
- 03-FTP和TFTP命令
http://www.h3c.com/cn/d_202101/1375275_30005_0.htm 1 FTP 1.1 FTP服务器配置命令 1.1.1 display ftp-server 1.1 ...