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

article/2025/9/15 3:54:41

特别强调~

本测试使用的是MySQL 8.0.27~ 8.0.27~ 8.0.27(因为不同版本命令可能会有差异哈)

打开两个终端,分别连接上MySQL,使用select @@global.transaction_isolation;查看隔离级别(间隙锁要在可重复读的隔离级别下)

​如果报类似ERROR 1193 (HY000): Unknown system variable 'tx_isolation'的错,一般是版本问题

# 老版本:select @@global.tx_isolation;select @@global.tx_isolation;# 5.8版本之后使用:select @@global.transaction_isolation;select @@global.transaction_isolation;

我们的测试表中的数据长这样

​事务1

终端A开启事务,查询id=5的数据(注意加上for update使用当前读)

select * from app_user_copy1 where id = 5 for update;

查看当前事务的锁信息

select * from performance_schema.data_locks;

  • 在MySQL 5.5以上、5.7.14以下的版本中,用户可以通过INFORMATION_SCHEMA下的INNODB_TRX、INNODB_LOCKS以及INNODB_LOCK_WAITS这三张表简单地监控并分析可能存在的锁问题

  • 在MySQL 8.0版本中,则需要使用performance_schema下的data_locks以及data_lock_waits获取相关的锁以及锁等待信息

  • 而MySQL版本在5.7.14到8.0之间的用户,只能通过其它手段间接的获取上述信息

我们从LOCK_MODE列中可以看到此事当前事务有两把锁(后面附有各个列的含义介绍)

  • 第一行LOCK_MODE为IX,即意向排他锁,属于表级锁

  • 第二行LOCK_MODE为X,REC_NOT_GAP,表示当前仅为行记录锁,且非间隙锁,属于行级锁

打开一个终端B,同样开启事务,更新id=5的行数据,会进入阻塞

update app_user_copy1 set name='test' where id=5;

​等到超时了就报错

​分别插入 id=3 和 id=7 的数据

INSERT INTO `app_user_copy1` (`id`, `name`, `email`, `phone`, `gender`, `password`, `age`, `create_time`, `update_time`) VALUES (3, '用户0', '123456@qq.com', '18582305042', 1, 'ef0641a4-7a7a-11ec-970f-7a9ea76b236f', 98, '2022-01-21 13:28:15', '2022-01-21 13:28:15');

​INSERT INTO `app_user_copy1` (`id`, `name`, `email`, `phone`, `gender`, `password`, `age`, `create_time`, `update_time`) VALUES (7, '用户0', '123456@qq.com', '18582305042', 1, 'ef0641a4-7a7a-11ec-970f-7a9ea76b236f', 98, '2022-01-21 13:28:15', '2022-01-21 13:28:15');

​都插入成功,说明当命中🎯注解索引时,临键锁退化为行级锁,是不会加间隙锁的

事务1结束,将数据恢复至测试开始前

事务2

终端A开启事务,查询id=3的数据(注意加上for update使用当前读)

select * from app_user_copy1 where id = 3 for update;

查看当前事务的锁信息

select * from performance_schema.data_locks;

​可以看到,此时LOCK_MODE为X,GAP,LOCK_DATA为5,即加了间隙锁,锁住 id=5 的行数据前的间隙;

终端B开启事务,更新 id=1 跟 id=5 两个边界信息

update app_user_copy1 set name='test' where id = 1; update app_user_copy1 set name='test' where id = 5;

​都更新成功,即当命中间隙时,会锁住当前间隙,并且不包括前后两条数据(即开区间)

事务2结束,将数据恢复至测试开始前

事务3

终端A开启事务,查询 id > 3 and id <=5 的数据(注意加上for update使用当前读)

select * from app_user_copy1 where id > 3 and id <= 5 for update;

​查看当前事务的锁信息

select * from performance_schema.data_locks;

可以看到,此时LOCK_MODE为X,LOCK_DATA为5,即加了临键锁,锁住 id=5 的行数据以及其前的间隙;

终端B开启事务,更新 id=1 、id=5 的信息

update app_user_copy1 set name='test' where id = 1; update app_user_copy1 set name='test' where id = 5;

id=1 更新成功

​id=5 更新失败

​插入id=2数据,插入失败

INSERT INTO `app_user_copy1` (`id`, `name`, `email`, `phone`, `gender`, `password`, `age`, `create_time`, `update_time`) VALUES (2, '用户0', '123456@qq.com', '18582305042', 1, 'ef0641a4-7a7a-11ec-970f-7a9ea76b236f', 98, '2022-01-21 13:28:15', '2022-01-21 13:28:15');

插入id=7数据,插入成功

INSERT INTO `app_user_copy1` (`id`, `name`, `email`, `phone`, `gender`, `password`, `age`, `create_time`, `update_time`) VALUES (7, '用户0', '123456@qq.com', '18582305042', 1, 'ef0641a4-7a7a-11ec-970f-7a9ea76b236f', 98, '2022-01-21 13:28:15', '2022-01-21 13:28:15');

即临键锁会锁住当前记录以及记录前的间隙(左开右闭区间)

事务3结束,将数据恢复至测试开始前

事务4

终端A开启事务,查询 id > 3 and id < 9 的数据(注意加上for update使用当前读)

select * from app_user_copy1 where id > 3 and id < 9 for update;

​查看当前事务的锁信息

 select * from performance_schema.data_locks;

可以看到,此时有两个行级锁

  • 第一个LOCK_MODE为X,LOCK_DATA为5,即加了临键锁,锁住 id=5 的行数据以及其前的间隙;

  • 第二个LOCK_MODE为X,GAP,LOCK_DATA为9,即加了间隙锁,锁住 id=9 的行数据前的间隙;

终端B开启事务,更新 id=1 、id=5 、id=9 的信息

update app_user_copy1 set name='test' where id = 1; update app_user_copy1 set name='test' where id = 5; update app_user_copy1 set name='test' where id = 9; 

id=1 更新成功

id=5 更新失败

​id=9 更新成功

​插入id=2数据,插入失败

INSERT INTO `app_user_copy1` (`id`, `name`, `email`, `phone`, `gender`, `password`, `age`, `create_time`, `update_time`) VALUES (2, '用户0', '123456@qq.com', '18582305042', 1, 'ef0641a4-7a7a-11ec-970f-7a9ea76b236f', 98, '2022-01-21 13:28:15', '2022-01-21 13:28:15');

​插入id=7数据,插入失败

INSERT INTO `app_user_copy1` (`id`, `name`, `email`, `phone`, `gender`, `password`, `age`, `create_time`, `update_time`) VALUES (7, '用户0', '123456@qq.com', '18582305042', 1, 'ef0641a4-7a7a-11ec-970f-7a9ea76b236f', 98, '2022-01-21 13:28:15', '2022-01-21 13:28:15');

​即当查询的是一段范围时,会锁住在符合查询条件的所有数据行,以及范围内的所有间隙(开区间,除非该数据行符合查询条件) 事务5 前面4个测试我们都是使用的唯一的主键索引,下面我们用普通索引试下( ̄∇ ̄)/ 终端A开启事务,查询 age=35 的数据(注意加上for update使用当前读)

select * from app_user_copy1 where age = 35 for update;

​查看当前事务的锁信息

 select * from performance_schema.data_locks;

可以看到,此时有3把行锁

  • 第一行LOCK_MODE列中为X,即加了临键锁

    • LOCK_DATA为35, 5指的是 age=35 的 id=5 的数据

    • 锁住的范围是 age=35 的行数据以及其前间隙

  • 第二行LOCK_MODE列中为X,REC_NOT_GAP

    • LOCK_DATA为5,即给 id=5 的行记录加了记录锁

  • 第三行LOCK_MODE列中为X,GAP,即加了间隙锁

    • LOCK_DATA为37, 24的指的是 age=37 的 id=24 的数据

    • 锁住的范围是 age=37 的行数据前的间隙

我们把数据库数据按照age升序排列,如下图

终端B开启事务,做如下更新操作

update app_user_copy1 set name='test' where age = 33; update app_user_copy1 set name='test' where age = 35; update app_user_copy1 set name='test' where age = 37;

age=33 更新成功

​age=35 更新失败

age=37 更新成功

插入 age=34 数据,插入失败

INSERT INTO `app_user_copy1` (`name`, `email`, `phone`, `gender`, `password`, `age`, `create_time`, `update_time`) VALUES ('用户0', '123456@qq.com', '18582305042', 1, 'ef0641a4-7a7a-11ec-970f-7a9ea76b236f', 34, '2022-01-21 13:28:15', '2022-01-21 13:28:15');

​插入 age=36 数据,插入失败

INSERT INTO `app_user_copy1` (`name`, `email`, `phone`, `gender`, `password`, `age`, `create_time`, `update_time`) VALUES ('用户0', '123456@qq.com', '18582305042', 1, 'ef0641a4-7a7a-11ec-970f-7a9ea76b236f', 36, '2022-01-21 13:28:15', '2022-01-21 13:28:15');

​插入 age=38 数据,插入成功

INSERT INTO `app_user_copy1` (`name`, `email`, `phone`, `gender`, `password`, `age`, `create_time`, `update_time`) VALUES ('用户0', '123456@qq.com', '18582305042', 1, 'ef0641a4-7a7a-11ec-970f-7a9ea76b236f', 38, '2022-01-21 13:28:15', '2022-01-21 13:28:15');

​上面测试中WHERE后的条件都是加了索引的,如果该字段未加索引,则会锁表(未命中不锁)

总结

  • LOCK_MODE列中为X,即加了临键锁,锁住的范围是LOCK_DATA中的行数据以及其前间隙(左开右闭)

  • LOCK_MODE列中为X,REC_NOT_GAP,锁住的是LOCK_DATA中的行数据

  • LOCK_MODE列中为X,GAP,锁住的是LOCK_DATA中的行数据前面的间隙(左开右开)


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

相关文章

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

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

mysql 间隙锁

一、什么是间隙锁&#xff1f; 间隙锁&#xff08;Gap Lock&#xff09;&#xff1a;锁加在不存在的空闲空间&#xff0c;可以是两个索引记录之间&#xff0c;也可能是第一个索引记录之前或最后一个索引之后的空间。 当我们用范围条件而不是相等条件索引数据&#xff0c;并请求…

什么是间隙锁

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

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

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

dubbo接口调试工具

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

Android Studio调试工具总结

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

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

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

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

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

通讯调试工具推荐

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

modbus调试工具的使用

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

两款常用的 MQTT 调试工具

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

简易Window BLE调试工具

简易Windows BLE调试工具 一、简介 Windows BLE调试工具是一款运行在Windows下的BLE调试软件&#xff0c;实现了扫描、连接、获取BLE设备上的服务以及向服务写入和读取数据的功能。 二、运行要求 系统需要使用Windows 10及以上的版本;需要电脑带有蓝牙功能或者使用外接蓝牙…

wsdl在线调试工具

1.下载soapui 2.进行调试 注:1.wsdl地址在测试服务器上一定要能联通 2.测试时如果是xml标签,需要进行转义 http://www.ku51.net/rehtml/ 3.在wsdl地址后面拼接?wsdl能够看到具体的接口信息 3.使用post进行请求示例

【sscom】 串口调试工具

这款串口调试工具我是经常使用的&#xff0c;这里推荐给大家&#xff0c;功能比较全面。 1、正常的串口调试功能。 2、可以保存一些经常发送的数据内容。 3、可以作为网络调试工具使用。 关注公众号&#xff1a;逸趣汇 微信号&#xff1a;yiquhui666 发送&#xff1a;010201 …

移动端开发调试工具

1、抓包工具Charles、Fiddler 平时只用抓取各种网络&#xff0c;需要设置手机的wifi代理 推荐指数2颗星 2、vConsole、eruda等调试库 这个方法需要在页面中插入一段 JS 脚本&#xff0c;这里以vConsole为例&#xff0c;导入vconsole.min.js&#xff0c;并实例化&#xff0c;…

串口通信工具android,串口调试工具手机版

串口调试工具手机版是一款针对OTG接口开发的串口调试应用&#xff0c;这款软件提供了文本、HEX码等多种格式&#xff0c;支持12个自定义按钮&#xff0c;支持自动重发功能&#xff0c;并提供了15种常用波特率&#xff0c;需要的朋友可以来西西下载串口调试工具手机版进行使用 串…

HTTP调试工具

HttpDebug HTTP协议调试工具 V1.02 英文绿色免费版 https://www.jb51.net/softs/43863.html postman的使用方法详解&#xff01;最全面的教程 https://www.cnblogs.com/jpfss/p/9082542.html 一 简介 Postman是一款功能超级强大的用于发送 HTTP 请求的 Chrome插件 。做web页…

Windows下的TCP/UDP网络调试工具-NetAssist以及Linux下的nc网络调试工具

已剪辑自: https://blog.csdn.net/ccf19881030/article/details/109370384 一、Windows下的网络调试工具-NetAssist 1、TCP服务端和客户端测试2、UDP服务端和客户端测试 二、Linux下的网络调试命令工具-nc 1、什么是nc2、nc的作用3、在CentOS7中安装nc命令工具[4、NetCat 官方…

串口调试工具推荐

作者&#xff1a;三十三重天 博客: http://www.zhouhuibo.club 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f61c; 在进行嵌入式开发时&#xff0c;总是要面对着来自终端的各种报文。不同的设备、终端厂商都有一套自己的报文协议&#xff0c;如何…

PostWomen websocket 调试工具

PostWomen是一款websocket调试工具,补充了post man没有websocket调试的遗憾 源代码 https://gitee.com/ichiva/post-women演示地址 新版浏览器已不支持 ws 链接&#xff0c;请使用 wss 链接实测本地 ws 链接任然可用,如 ws://127.0.0.1 或 ws://localhost http://ichiva.gi…