MySQL8 间隙锁在11种情况下的锁持有情况分析

news/2024/7/24 12:48:09 标签: mysql, 间隙锁

测试环境及相关必要知识

测试环境为mysql 8 版本

间隙锁(Gap Lock):用于锁定索引范围之间的间隙,防止其他事务在此间隙中插入新记录。间隙锁主要用于防止幻读问题。

在可重复读的隔离级别下默认打开该锁机制,解决幻读问题,也可手动修改配置文件关闭该锁机制,该锁机制为innodb自动决定间隙范围上锁,无需SQL显式声明锁。

表结构如下
在这里插入图片描述
数据如下
在这里插入图片描述
Mysql 运行中事务可以在表 information_schema.INNODB_TRX 中查看
在这里插入图片描述

Mysql 运行中事务持有的锁可以在表 performance_schema.data_locks 中查看
(一行分割两张图了)
在这里插入图片描述
在这里插入图片描述

Mysql 运行中事务等待持有锁的事务可以在表 performance_schema.data_lock_waits 中查看
在这里插入图片描述

LOCK MODE(锁模式)将出现的锁模式值和解释

S:共享锁(Shared Lock),允许其他事务获取相同对象的共享锁,但不允许排它锁。
X:排它锁(Exclusive Lock),在事务持有排它锁期间,其他事务无法获取相同对象的共享锁或排它锁。
IS:意向共享锁(Intention Shared Lock),表示事务准备获取一个表中某些行的共享锁。
IX:意向排它锁(Intention Exclusive Lock),表示事务准备获取一个表中某些行的排它锁。
SIX:共享意向排它锁(Shared Intention Exclusive Lock),表示事务准备获取一个表中某些行的共享锁,但也准备获取这些行的排它锁。
REC_NOT_GAP是MySQL InnoDB存储引擎中的一个特殊锁模式,用于锁定记录(行)而非间隙(gap)

注意:接下来将看到很多意向锁,意向排他锁并不等于持有了排它锁,只是表明有持有该锁的意向!
LOCK TYPE(锁类型)可能出现的是RECORD (行锁)、TABLE(表锁)

下面的各种情况下MySQL InnoDB锁持有情况的结构是先展示SQL,后展示持有锁的截图
持有锁截图中重要的字段为INDEX_NAME 索引名 LOCK_TYPE 锁类型 LOCK_MODE 锁模式 LOCK_STATUS 锁状态 LOCK_DATA 锁数据

走唯一索引的主键id+指定值+有值情况

begin ;
select * from t_gap_demo where id  = 3 for update ;

结果:对id=3的行记录上了行排他锁,当前表的意向排他锁
在这里插入图片描述

走唯一索引的主键id+指定值+无值情况

begin ;
select * from t_gap_demo where id  = 4 for update ;

插入id=4数据被阻塞,证明(3,]间隙已被锁定,插入id=8数据成功,插入id=2数据成功
结果:对数据7持有了排他锁、间隙锁范围为(3,7] 左开右闭原则
在这里插入图片描述

走唯一索引的主键id+指定范围+有值情况

begin ;
select * from t_gap_demo where id  between 3 and 8 for update ;

结果:持有了主键索引上的1、3、7、15四行的行锁且无间隙锁,持有表排它锁意向锁,额外还持有了普通索引age上的所有值的排它锁及间隙锁(0到正无穷都锁住了,这个字段没有负数)
这个结果挺让人震惊的,这句SQL居然持有了这么多锁,而且我测试插入id=2,age=1的记录是无法插入的,一直被阻塞。证明age整个范围的间隙锁都是被锁住了的,无法插入任何数据。
在这里插入图片描述
额外我还测试了一下该情况下update语句的锁情况

begin ;
update   t_gap_demo set age = 1 where id  between 3 and 8  ;

结果是锁住了(3,7] (7,15]间隙锁,3、7、15行锁,附带基本的表排他锁意向锁,至于为啥select语句时锁住了整个age间隙,还需要后续研究,有懂的大佬评论一下
在这里插入图片描述

走唯一索引的主键id+指定范围+无值情况

begin ;
select * from t_gap_demo where id  between 18 and 28 for update ;

id = 14可以插入,id = 16无法插入,阻塞
结果:持有了排它锁,锁住最后一行记录15到正无穷
在这里插入图片描述

begin ;
select * from t_gap_demo where id  between 10 and 12 for update ;

于是我又好奇假设这个区间无值,但是属于某个间隙呢
结果:持有了这个范围所在间隙的间隙锁 (7,15],15这个行记录的排它锁,表意向排它锁
在这里插入图片描述

走普通索引的age+指定值+有值情况

begin ;
select * from t_gap_demo where age  = 3 for update ;

结果:主键id=1的记录行锁排它锁锁定、普通索引上3,1 6,3全部锁定行记录加间隙,表意向排它锁
在这里插入图片描述

走普通索引的age+指定值+无值情况

begin ;
select * from t_gap_demo where age  = 4 for update ;

结果:持有了这个不存在的id处于的这个间隙的间隙锁和两个行记录的排它锁,表意向排它锁
在这里插入图片描述

走普通索引的age+指定范围+有值情况

begin ;
select * from t_gap_demo where age  between 20 and 40 for update ;

结果:持有了整个范围涉及的间隙的间隙锁、涉及行的排他锁,涉及行记录的主键记录的排它锁(不带间隙锁),表意向排它锁
在这里插入图片描述

走普通索引的age+指定范围+无值情况

begin ;
select * from t_gap_demo where age  between 78 and 88 for update ;

结果:持有age记录最大值到正无穷的间隙锁,表意向排它锁
在这里插入图片描述

拓展:非索引字段范围锁定

begin ;
select * from t_gap_demo where age  between 1 and 15 for update ;

结果:持有了整个id范围内所有行记录的排它锁和所在区间(包括左右无穷)的间隙锁,尝试插入id=2,id=16记录都是阻塞状态
在这里插入图片描述

总结

经过各种情况下事务对数据的加排它锁测试发现,mysql 8 innodb引擎会对涉及的数据和间隙都加上排他、间隙锁,甚至在普通索引时还会对涉及数据的主键索引也加上不带间隙锁的排它锁(X,REC_NOT_GAP),在非索引字段范围锁定时会对整个数据和间隙锁定,这告诉我们在使用时要注意,追求性能时少使用悲观锁,尽量避免锁竞争、避免死锁,尽量走主键索引或索引、尽量少锁定资源或只锁定最小范围数据、尽量精确操作某行数据,尽量让事务执行时间短,尽量避免同时事务并发操作同间隙内数据以避免死锁。


http://www.niftyadmin.cn/n/5071945.html

相关文章

[动手学深度学习]注意力机制Transformer学习笔记

动手学深度学习(视频):68 Transformer【动手学深度学习v2】_哔哩哔哩_bilibili 动手学深度学习(pdf):10.7. Transformer — 动手学深度学习 2.0.0 documentation (d2l.ai) 李沐Transformer论文逐段精读&a…

番外项目---Vim编辑器

Task01: 1.在/tmp目录下建立一个名为mytest的目录,进入mytest目录当中; 2.将/etc/man_db.conf复制到上述目录下面,使用vim打开目录下的man_db.conf文件; 3.在vim中设定行号,移动到第58行,向右移动15个字符,请问你看到…

嵌入式处理趋势,第一部分:超集成MCU

当今的嵌入式微控制器(MCU)是协同和创新的惊人例子。单个芯片上可容纳30,000至2百万个门,直到最近,各种集成的组件和模块都被视为独立的高级IC。 例如,当前典型的MCU设备(下面的图1)可能包含以…

I/O多路复用【Linux/网络】(C++实现select、poll和epoll服务器)

阅读前导: “I/O 多路复用”处于知识树中网络和操作系统的最后,因此本文默认读者有计算机网络和操作系统的基础。 1. 引入:C10K 问题 c10k 问题是指如何让一个服务器同时处理超过 10000 个客户端的连接,这是一个网络编程中的经…

【不定期更新】什么是Linux内核

2023年10月7日,周日晚上 目录 硬件资源管理 进程调度 文件系统管理 设备驱动 网络功能 Linux内核中的主要网络功能 安全 系统调用接口 Linux内核提供了哪些系统调用接口? 总结 Linux内核是Linux操作系统的核心,它起到以下主要的作用…

3.primitive主数据类型和引用 认识变量

3.1 声明变量 Java注重类型。它不会让你做出把长颈鹿类型变量装进兔子类型变量中这种诡异又危险的举动——如果有人对长颈鹿调用“跳跃”这个方法会发生什么样的悲剧?并且它也不会让你将浮点数类型变量放进整数类型的变量中,除非你先跟编译器确认过数字…

cpu的指令重排,禁用办法

上一篇博客 volatile关键字总结-CSDN博客,我们讲了两个volatile变量可以限制编译器对指令的重排,但是限制不了cpu层面的指令重排 这篇博客开始,我们演示下cpu层面的指令重排,以及如何禁止cpu层面的指令重排 实验一:复…

【基于STM32OpenCV的车载机器人的抓取控制软件设计】

这里写自定义目录标题 本科优秀毕业论文《基于STM32&OpenCV的车载机器人的抓取控制软件设计》摘要:Abstract:前 言1方案设计与论证2机器人硬件电路设计3机器人软件设计4系统主要功能测试5 结 论参考文献本科优秀毕业论文《基于STM32&OpenCV的车载机器人的抓取控制软件…