MySQL的间隙锁

article/2025/9/15 22:40:21

一、、为什么要引入间隙锁

MySQL引入间隙锁(Gap Lock),是为了在可重复读事务隔离级别中,解决幻读问题锁引入的锁机制。

二、幻读

2.1、什么是幻读

幻读是指,当一个事务先后两次查询同一个范围的时候,查到的结果不同,这是因为第二次这个事务查到了其他事务对数据所做的更改。
在这里插入图片描述
这里,先后执行了Q1 ~ Q3 3次select *** for update读,读到的结果不同:
1)sessionB由于执行了update t set d=5 where id=0, 导致新增了一条满足d=5条件的记录(0,0,5)
2)由于sessionC插入了一条记录,导致新增了一条满足d=5条件的记录(1,1,5)

在可重复读级别下,查询操作都是“快照读”,是不会看到其他事务新插入的记录的。因此,幻读在“当前读”的情况下才会出现。

2.2、间隙锁导致的死锁

在这里插入图片描述
1)session A 执行 select … for update 语句,由于 id=9 这一行并不存在,因此会加上 间隙锁 (5,10)
2)session B 执行 select … for update 语句,同样会加上间隙锁 (5,10),间隙锁之间不会冲突,因此这个语句可以执行成功
3)session B 试图插入一行 (9,9,9),被 session A 的间隙锁挡住了,只好进入等待;
4)session A 试图插入一行 (9,9,9),被 session B 的间隙锁挡住了

此时,会产生死锁。InnoDB 的死锁检测马上就发 现了这对死锁关系,让 session A 的 insert 语句报错返回了。
间隙锁的引入,可能会导致同样的语句锁住更大的范围,这其实是影响了性能的。

三、什么是间隙锁

间隙锁(Gap Lock):
1)间隙锁锁定的是索引BTree+叶子节点的next指针
2)间隙锁主要用于解决可重复读事务隔离级别中的幻读问题。

快照读:
在可重复读事务隔离级别下,快照读读到的是数据的当前版本或历史版本。所以快照读无需加锁也可以防止幻读。

当前读:
select…lock in share mode,select…for update
update,delete,insert
当前读:读取的是记录的最新版本,所以就需要通过加锁(行锁、间隙锁、表锁)的方式,使得被当前读读过的数据不能被新增修改或者删除,换句话说再来一次当前读要返回相同的数据

四、间隙锁的使用场景

数据库表:

CREATE TABLE `z` (`id` int(11) NOT NULL AUTO_INCREMENT,`b` int(11) DEFAULT NULL,`c` int(255) NOT NULL DEFAULT '0',PRIMARY KEY (`id`),KEY `b` (`b`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;b字段是索引,id是主键INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('1', '1', '0');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('3', '6', '1');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('5', '4', '2');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('7', '8', '3');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('8', '10', '4');

BTree+的索引:
在这里插入图片描述

锁加在哪里呢?
begin; select * from z where b = 6 for update;

这条sql语句之后看看我们 需要做什么才能保证不发生幻读。
1)不能插入b为6的数据
2)不能删除b为6的数据
3)不能修改b为6的数据
4)不能把别的数据修改为b为6

突然一看挺复杂的,这个锁要怎么加呢,mysql大牛灵机一动,给叶子节点5的next指针加锁,给叶子节点3加行锁,给叶子节点3的next指针加锁。如下图所示

在这里插入图片描述
两个next指针锁解决了插入b为6或者把别的数据修改为b为6,行锁解决了修改b为6的行
这样加锁虽然解决了上述问题,但是也带来了副作用:
例如
INSERT INTO study.z (id, b, c) VALUES (‘6’, ‘4’, ‘0’);
执行上述语句会被block, 因为按照索引结构这条数据会插入到叶子结点5和3之间,会修改叶子节点5的next指针,虽然这条sql没有破坏上述的4个红色条件但是依然被阻塞了

INSERT INTO study.z (id, b, c) VALUES (‘4’, ‘4’, ‘0’);
这条语句可插入成功因为这条数据会插入在1的后面5的前面。

五、间隙锁的范围

begin;
select * from z where id=4 for update;
会锁住主键索引叶子节点的3的next指针

begin;
select * from z where id=3 for update;
间隙锁会退化为行锁只锁叶子节点3 ,为什么因为没必要。不加间隙锁也不会打破上述的红色4个条件

begin;
select * from z where id>4 for update;
叶子节点3及之后所有节点会加行锁并且他们的next指针会加锁

begin;
select * from z where c=2 for update;
会发生锁表,因为c没有索引结构能存储行锁或者间隙锁。


http://chatgpt.dhexx.cn/article/ppwM7vJX.shtml

相关文章

MySQL间隙锁(幻读解决原理)

文章目录 一、间隙锁概念二、测试间隙锁范围加锁场景1:用不可重复的主键id测试间隙锁场景2:用可重复的age(有索引)测试间隙锁场景3:实际情况需要具体分析用的到底是行锁还是表锁 三、测试等值间隙锁1. 测试不能重复的主…

mysql隔离级别RR下的行锁、临键锁、间隙锁详解及运用

一:mysql 锁的基本概念 锁:悲观锁、乐观锁 悲观锁:写锁 for update、读锁for share 写锁:只允许当前事务读写,其它事务全部等待,包括读取数据,锁的数据范围需要具体分析 读锁:允…

MySQL行锁、表锁、间隙锁详解

前言 我们前几篇讲了索引是什么,如何使用explain分析索引使用情况,如何去优化索引,以及show profiles分析SQL语句执行资源消耗的学习。今天我们来讲讲MySQL的各种锁,这里存储引擎我们使用InnoDB; 准备工作 创建表 t…

Mysql_行锁、临键锁、间隙锁的理解

目录 行锁间隙锁临键锁总结 行锁 行锁,也称为记录锁。 当我们针对主键或者唯一索引加锁的时候,Mysql默认会对查询的这一行数据加行锁,避免其他事务对这一行数据进行修改。 间隙锁 间隙锁,顾名思义,就是锁定一个索引…

【MySQL】MySQL的锁机制 - 记录锁、间隙锁、临键锁

目录 一、参考链接二、总结1、间隙锁的目的2、什么时候产生间隙锁?3、间隙锁锁定的范围4、需要注意的点(重要) 三、案例建表案例1:查询已存在的单条记录案例2:查询不存在的记录案例3:查询多条记录(范围查询) 四、其余验…

MySQL的锁机制 - 记录锁、间隙锁、临键锁

记录锁(Record Locks) 记录锁是 封锁记录,记录锁也叫行锁,例如: SELECT * FROM test WHERE id1 FOR UPDATE; 它会在 id1 的记录上加上记录锁,以阻止其他事务插入,更新,删除 id1 这一行。 记录锁、间隙锁…

行锁、间隙锁、next-key锁

参考博客:cmysql锁(九)innodb下的记录锁,间隙锁,next-key锁 - 简书 Mysql 行锁、间隙锁和next-key锁详解_程序员掉头发的博客-CSDN博客_行锁 间隙锁 行锁(Record Lock): 对索引记录加锁。间隙锁(Gap Lock…

mysql记录锁、间隙锁、临键锁

名词解释 记录锁:record lock,即锁住一条记录 间隙锁:gap lock,即锁定一个区间,左开又开 临键锁:记录锁间隙锁锁定的区间,左开右闭 mysql如何加锁 假设有如下数据 其中,id 是主键索引(唯一索…

【MySQL】记录锁?间隙锁?临键锁?到底锁了些什么?这一篇帮你捋清楚( ̄∇ ̄)/

特别强调~ 本测试使用的是MySQL 8.0.27~ 8.0.27~ 8.0.27(因为不同版本命令可能会有差异哈) 打开两个终端,分别连接上MySQL,使用select global.transaction_isolation;查看隔离级别&#xff08…

MySQL的锁机制——记录锁、间隙锁、临键锁

记录锁(Record Locks) 记录锁锁住的是索引记录,记录锁也叫行锁。如果使用索引作为条件命中了记录,那么就是记录锁,被锁住的记录不能被别的事务插入相同的索引键值,修改和删除。 例如: select * from test_table whe…

mysql 间隙锁

一、什么是间隙锁? 间隙锁(Gap Lock):锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。 当我们用范围条件而不是相等条件索引数据,并请求…

什么是间隙锁

中心思想 间隙锁锁的是索引叶子节点的next指针。 意义 解决了mysql RR级别下是幻读的问题。 快照读 在RR隔离级别下:快照读有可能读到数据的历史版本,也有可能读到数据的当前版本。所以快照读无需用锁也不会发生幻读的情况。 当前读 当前读&#…

MySql进阶-间隙锁(gap-key)

文章目录 Innodb锁算法关闭Gap LockGap-key 解决的问题间隙锁影响MVCC 核心原理ReadView 可参考 快照读,当前读可参考 参考《InnoDB存储引擎》 注意:gap-key是innodb存储引擎来解决当前读的幻读问题的。对于隔离级别下的可重复读只能解决快照读的幻读问题…

dubbo接口调试工具

最近的项目使用来dubbo进行开发,虽然可以使用telne客户端t进行dubbo的接口的调试,但总感觉调试起来不太方便,并且限制太多,于是抽了点时间出来编写了一个dubbo的客户端可视化调试工具,功能虽简单但可以快速的调试dubbo…

Android Studio调试工具总结

前言:写代码不可避免有Bug,通常情况下除了日志最直接的调试手段就是debug;当我们的程序出现bug时,调试可以快速的找到bug。进入调试状态,我们可以清楚的了解程序的整个执行过程,可以对内存的数据进行监视。…

串口调试、udp 调试、tcp 调试,websocket 调试,通讯调试工具

简介 一个通讯测试工具,QSAK(Qt Swiss Army Knife)是一款基于Qt开源框架打造的多功能、跨平台调试工具。目前支持串口调试、udp 调试、tcp 调试及 websocket 调试等。支持 Windows、Linux、raspberry pi 等平台。 免费、开源、绿色、免安装…

chrome--浏览器调试工具详解

chrome浏览器开发调试工具打开方式:F12键 一,常用面板介绍 1.定位小箭头按钮(左边第一个): 选中Elements面板,并启动该按钮,可以在页面中定位相应元素的源代码位置,或者选择源代码位置可定位到页面相应的元…

通讯调试工具推荐

CommBox通讯调试工具-简单说明 工具支持:串口通讯、串口代理、TCP、UDP、Telnet、Ping、TFtp、串口监视、以太网嗅探等通讯测试 1、本工具支持预定义命令,命令可以进行分组,由树形控件管理。点击“命令编辑”即可编辑预…

modbus调试工具的使用

modbus调试工具的使用分为2部分,2者互相不影响,可以单独使用。 一、根据IP进行模拟通信 二、根据COM进行模拟通信 一、根据IP进行模拟通信 1.安装完成ModbusPollSetup64Bit后,输入注册码进行注册;安装完成ModbusSlaveSetup64Bi…

两款常用的 MQTT 调试工具

文章目录 一、前言二、预备知识三、MQTTBox1、介绍2、下载3、入门使用4、负载测试 四、MQTT.fx1、介绍2、下载3、入门使用4、JS 脚本 一、前言 我们可以使用 MQTT 客户端来测试 MQTT 的通讯功能,这里介绍常用的两款工具 MQTTBox 和 MQTT.fx 。 二、预备知识 MQTT…