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

article/2025/9/15 23:36:25

文章目录

    • Innodb锁算法
    • 关闭Gap Lock
    • Gap-key 解决的问题
    • 间隙锁影响
    • MVCC 核心原理
    • ReadView

可参考
快照读,当前读可参考
参考《InnoDB存储引擎》
注意:gap-key是innodb存储引擎来解决当前读的幻读问题的。对于隔离级别下的可重复读只能解决快照读的幻读问题。

  • 快照读, 读取专门的快照 (对于RC,快照(ReadView)会在每个语句中创建。对于RR,快照是在事务启动时创建的)
    简单的select操作即可
    针对的也是select操作
  • 当前读, 读取最新版本的记录, 没有快照。 在InnoDB中,当前读取根本不会创建任何快照。
    select … lock in share mode
    select … for update
    insert
    update
    delete
    针对如下操作, 会让如下操作阻塞:
    insert
    update
    delete

在RR(可重复读)级别下, 快照读是通过MVVC(多版本控制)和undo log来实现的,
当前读是通过手动加record lock(记录锁)和gap lock(间隙锁)来实现的。所以从上面的显示来看,如果需要实时显示数据,还是需要通过加锁来实现。这个时候会使用next-key技术来实现。

tips:SELECT…FOR UPDATE对读取的行记录加一个X锁,其他事务不能对已锁定的行加上任何锁。SELECT…LOCK IN SHARE MODE对读取的行记录加一个S锁,其他事务可以向被锁定的行加S锁,但是如果加X锁,则会被阻塞。
使用这两种一致性锁定读的办法注意开启事务,提交事务,来锁定与释放锁。

Innodb锁算法

  • Record Lock:单个行记录上的锁
  • Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
  • Next-Key Lock∶Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身

对于Record Lock会去锁索引,如果表在建立的时候没有设置任何一个索引,那么innodb会使用隐式的主键来当这个索引来锁定。

Gap Lock的作用是为了阻止多个事务将记录插入到同一范围内。

InnoDB存储引擎会对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引本身,而不是范围。这种情况发生在查询的列是唯一索引的情况下。

若唯一索引由多个列组成,而查询仅是查找多个唯一索引列中的其中一个,那么如果查询其实是范围类型查询,而不是精准类型查询,InnoDB存储引擎会使用Next-Key Lock进行锁定。

在InnoDB存储引擎中,对于INSERT的操作,其会检查插入记录的下一条记录是否被锁定,若已经被锁定,则不允许查询。

关闭Gap Lock

  • 将事务的隔离级别设置为READ COMMITTED
  • 将参数innodb_locks_unsafe_for_binlog设置为1

Gap-key 解决的问题

在默认的事务隔离级别下,即REPEATABLE READ下,InnoDB存储引擎采用Next-Key Locking机制来避免幻读。幻读会导致即使把所有的记录都加上锁,还阻止不了新插入的记录。

在同一事务下,连续执行两次同样的SQL语句可能导致不同的结果,第二次的SQL语句可能会返回之前不存在的行。
在可重复读下,两次当前读语句可能会出现幻读问题。而Gap-Key便是用来解决当前读的幻读的问题的。

举例(细节略),该例子是说明在可重复读下,mysql在没有解决幻读时,两个事务读会出现幻读的问题。:

事务1事务2
select * from table where int>2 for update
结果 3 5
insert into table (4)
select * from table where int >2 for update
结果3 4 5

由例子可以看出,如果不加间隙缩,事务的两次当前读会读到之前没有行,即幻读。

间隙锁和行锁合称 next-key lock,每个 next-key lock 是前开后闭区间。在同一事务内,前后两次执行同一sql语句,结果不一样。而当使用Gap-key的时候,就可以在 (2,+∞)加上锁,禁止其他事务进行插入。

InnoDB存储引擎默认的事务隔离级别是REPEATABLE READ,在该隔离级别下,Innobb其采用Next-Key Locking的方式来加锁,解决幻读问题。

对于非索引字段进行update,delete或select … for update操作,代价极高。所有记录上锁,以及所有间隔的锁。
对于索引字段进行上述操作,代价一般。只有索引字段本身和附近的间隔会被加锁。
对于select for update 如果不走索引,那么会走全表扫描,增加的gap_lock会非常多。

主键索引的间隙上也要有Gap lock保护的。

MVCC 具体解决了以下问题:

并发读-写时:可以做到读操作不阻塞写操作,同时写操作也不会阻塞读操作。

解决脏读、幻读、不可重复读等事务隔离问题,但不能解决上面的写-写(需要加锁)问题。

间隙锁影响

间隙锁的引入,可能会导致同样的语句锁住更大的范围,这其实是影响了并发度的。
如果把隔离级别设置为读提交的话,就没有间隙锁了。但同时,你要解决可能出现的数据和日志不一致问题,需要把 binlog 格式设置为 row。

MVCC 核心原理

可参考

它的实现原理主要是版本链,undo日志 ,Read View来实现的。

InnoDB 存储引擎的介绍了数据页的行格式,对于使用它的表来说,表中的聚簇索引都包含三个隐藏列:

在这里插入图片描述
每次对记录进行改动,都会记录一条 undo 日志,每条 undo 日志也都有一个 roll_pointer 属性(INSERT 操作对应的 undo 日志没有该属性,因为该记录并没有更早的版本),可以将这些 undo 日志都连起来,串成一个链表,所以现在的情况就像下图一样:

在这里插入图片描述
对该记录每次更新后,都会将旧值放到一条 undo 日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被 roll_pointer 属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。

另外,每个版本中还包含生成该版本时对应的事务 id。于是可以利用这个记录的版本链来控制并发事务访问相同记录的行为,那么这种机制就被称之为多版本并发控制(MVCC)。

ReadView

改动的记录都存在在 undo 日志中,那如果一个日志需要查询行记录,需要读取哪个版本的行记录呢?

1️⃣ 对于使用 READ UNCOMMITTED 隔离级别的事务来说,由于可以读到未提交事务修改过的记录,所以直接读取记录的最新版本就好了。

2️⃣ 对于使用 SERIALIZABLE 隔离级别的事务来说,InnoDB 使用加锁的方式来访问记录,不存在并发问题。

3️⃣ 而对于使用 READ COMMITTED 和 REPEATABLE READ 隔离级别的事务来说,都必须保证读到已经提交了的事务修改过的记录,也就是说假如另一个事务已经修改了记录但是尚未提交,是不能直接读取最新版本的记录的。

核心问题就是: READ COMMITTED 和 REPEATABLE READ 隔离级别在不可重复读和幻读上的区别在哪里?这两种隔离级别对应的不可重复读与幻读都是指同一个事务在两次读取记录时出现不一致的情况,这两种隔离级别关键是需要判断版本链中的哪个版本是当前事务可见的。

ReadView 就是用来解决这个问题的,可以帮助我们解决可见性问题。 事务进行快照读操作的时候就会产生 Read View,它保存了当前事务开启时所有活跃的事务列表。

注:这里的活跃指的是未提交的事务。

每一个事务在启动时,都会生成一个 ReadView,用来记录一些内容,ReadView 中主要包含 4 个比较重要的属性:

在这里插入图片描述
其中,max_trx_id并不是指m_ids中的最大值,因为事务 id 是递增分配的,假如现在有 id 为 1,2,3 这三个事务,之后 id 为 3 的事务提交了。那么一个新的读事务在生成 ReadView 时,m_ids 就包括 1 和 2,min_trx_id 的值就是 1,max_trx_id 的值就是 4。

再有了 ReadView 之后,在访问某条记录时,只需要按照下边的步骤判断记录的某个版本是否可见:

  • trx_id = creator_trx_id ,可访问
    如果被访问版本的 trx_id 属性值与 ReadView 中的 creator_trx_id 值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。

  • trx_id < min_trx_id ,可访问
    如果被访问版本的 trx_id 属性值小于 ReadView 中的 min_trx_id 值,表明生成该版本的事务在当前事务生成 ReadView 前已经提交,所以该版本可以被当前事务访问。

  • trx_id >= max_trx_id ,不可访问
    如果被访问版本的 trx_id 属性值大于或等于 ReadView 中的 max_trx_id 值,表明生成该版本的事务在当前事务生成 ReadView 后才开启,所以该版本不可以被当前事务访问。

  • min_trx_id <= trx_id < max_trx_id,存在 m_ids 列表中不可访问
    如果被访问版本的 trx_id 属性值在 ReadView 的 min_trx_id 和 max_trx_id 之间,那就需要判断一下 trx_id 属性值是不是在 m_ids 列表中,如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问。

  • 某个版本的数据对当前事务不可见

  • 如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性,依此类推,直到版本链中的最后一个版本。如果最后一个版本也不可见的话,那么就意味着该条记录对该事务完全不可见,查询结果就不包含该记录。

在 MySQL 中,READ COMMITTED 和 REPEATABLE READ 隔离级别的的一个非常大的区别就是它们生成 ReadView 的时机不同。


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

相关文章

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…

嵌入式开发<网络调试工具>

嵌入式开发<网络调试工具> 前言1&#xff0c;设备参数分类2&#xff0c;设备参数修改3&#xff0c;调试工具软件 一、软件界面二、功能说明1.网络设置1&#xff09;TCP Client设置A&#xff0c; 协议类型&#xff1a;B&#xff0c; 远程主机地址&#xff1a;C&#xff0c…

Linux串口调试工具

linux系统下串口调试和应用开发时配合串口调试工具必不可少。下面对常用的一些串口工具做一下汇总&#xff0c;包含&#xff1a;minicom/cutecom/picocom/putty/tty_uart 可供工程师参考。 实验环境&#xff1a; OS: Ubuntu16.04 ------------------------------------------…

android js调试工具,鬼鬼JS调试工具

鬼鬼JS调试工具是一款非常实用的JS调试软件&#xff0c;这里带给大家最新版本&#xff0c;新增了一些解密等功能&#xff0c;对于JS调试工作者或者感兴趣的朋友提供稳定和强大的调试支持。鬼鬼JS调试工具具有直观的界面设计&#xff0c;功能十分全面&#xff0c;有需要的朋友欢…

前端必须知道的调试工具

Bug和Debug Bug的起源&#xff1a; 当时人们还在使用第一代真空计算机&#xff08;马克二型&#xff09;&#xff0c;这种计算机是依靠控制电流来改变开关&#xff0c;从而实现控制&#xff0c;但是它会发出大量的热和光。 1949年9月9日&#xff0c;天气非常炎热&#xff0c…