0

0

什么是间隙锁(Gap Lock)?它解决了什么问题?

betcha

betcha

发布时间:2025-09-10 08:06:01

|

844人浏览过

|

来源于php中文网

原创

间隙锁通过锁定索引记录间的“间隙”防止其他事务插入新记录,从而避免幻读。在REPEATABLE READ隔离级别下,执行范围查询时,InnoDB不仅锁定行记录,还锁定记录之间的间隙、首记录前和末记录后的范围。例如查询id BETWEEN 10 AND 20时,会锁定(5,12)和(12,25)等间隙(假设有id为5、12、25的记录),阻止其他事务插入id在该范围内的新行。间隙锁基于B+树索引实现,影响范围可能超出预期,增加锁冲突风险。实际应用中,可通过调整隔离级别至READ COMMITTED、优化索引设计、缩小事务范围、避免不必要的锁定、监控锁状态及分批处理等方式优化间隙锁带来的并发问题。

什么是间隙锁(gap lock)?它解决了什么问题?

间隙锁(Gap Lock)是InnoDB存储引擎在实现特定事务隔离级别(主要是

REPEATABLE READ
)时,为了解决幻读(Phantom Read)问题而引入的一种锁机制。简单来说,它锁定的不是具体的某一行记录,而是索引记录之间的“间隙”,或者说是某个范围。这能有效防止新的记录被插入到这个被锁定的范围内,从而保证事务在多次读取同一范围数据时,看到的数据集是一致的。

间隙锁的出现,坦白讲,是数据库设计者在追求数据一致性与并发性之间找到的一个平衡点。当我们的事务需要确保在某个数据范围内,不会有新的数据凭空出现或消失时,间隙锁就发挥了它的作用。它解决了这样一个痛点:即便我们已经锁定了查询到的所有行记录,但在并发环境下,如果其他事务在这个范围里插入了新行,我们的后续查询依然会“看到”这些新行,这就是幻读。间隙锁正是为了弥补这种“空隙”而生的。

间隙锁是如何避免幻读(Phantom Read)的?

要理解间隙锁如何避免幻读,我们得先搞清楚幻读到底是什么。想象一下,你在一个银行系统里,先查询了所有余额在100到200之间的账户。如果此时,另一个柜员恰好新开了一个账户,余额是150,并提交了。那么当你再次查询同样范围的账户时,你会发现多了一个之前没见过的账户。这就是幻读,你的事务在逻辑上认为的“不变”被打破了。

间隙锁正是为了防止这种情况发生。当一个事务在

REPEATABLE READ
隔离级别下,执行一个范围查询并需要锁定这些数据(比如
SELECT ... WHERE id BETWEEN 10 AND 20 FOR UPDATE;
),InnoDB不仅仅会锁定
id
在10到20之间的所有现有记录,它还会锁定这些记录之间的“间隙”,以及10之前的间隙和20之后的间隙(如果它们是边界)。

具体来说,如果你的表里有

id
为5, 12, 25的记录,当你查询
id BETWEEN 10 AND 20
时,间隙锁会锁定:

  • (5, 12)
    这个间隙:防止新的
    id
    在5到12之间插入。
  • (12, 25)
    这个间隙:防止新的
    id
    在12到25之间插入。
  • 如果查询范围是
    id > 10
    ,那么它会锁定
    (10, 12)
    (12, 25)
    ,以及
    (25, +∞)

这样一来,无论其他事务尝试在

(5, 12)
(12, 25)
这两个区间内插入任何新记录,都会被当前事务的间隙锁阻塞,直到当前事务提交或回滚。这确保了在当前事务的生命周期内,你再次执行相同的范围查询时,不会看到任何“凭空出现”的新行,从而有效杜绝了幻读。

间隙锁的工作原理与影响范围是怎样的?

间隙锁的工作原理,说白了,就是InnoDB利用了B+树索引的特性。它不是在内存中画一个“锁定的区域”,而是通过在索引结构中的特定位置设置锁标记来实现的。当一个事务需要锁定某个范围时,InnoDB会找到这个范围的起始和结束索引键值,然后锁定这些键值所代表的记录以及它们之间的“空隙”。值得注意的是,间隙锁是作用于索引的,所以一个高效的索引设计对于间隙锁的性能至关重要。

改图鸭AI图片生成
改图鸭AI图片生成

改图鸭AI图片生成

下载

间隙锁的影响范围,有时候会超出我们的预期,这正是它可能导致死锁和并发问题的原因。它会锁定:

  1. 索引记录之间的间隙:这是最核心的部分。
  2. 第一个索引记录之前的间隙:如果你的查询范围从索引的最小值开始,或者查询的起始值小于表中最小的索引值,那么从负无穷到第一个索引记录之间的间隙也会被锁定。
  3. 最后一个索引记录之后的间隙:同理,如果查询范围到索引的最大值结束,或者查询的结束值大于表中最大的索引值,那么从最后一个索引记录到正无穷之间的间隙也会被锁定。

举个例子,假设我们有一个

users
表,
id
列是主键,有数据
id = 1, 5, 10, 15
。 如果一个事务执行
SELECT * FROM users WHERE id > 7 AND id < 12 FOR UPDATE;
那么,InnoDB会锁定:

  • 记录
    id=10
    (这是一个行锁)。
  • (5, 10)
    这个间隙。
  • (10, 15)
    这个间隙。 这意味着,在事务提交前,其他事务无法插入
    id
    为6、7、8、9、11、12、13、14的记录。可以看到,间隙锁锁定了一个比我们查询结果更大的范围,这在某些高并发场景下,确实会增加锁冲突的可能性。

在实际应用中,我们应该如何理解和优化间隙锁?

理解间隙锁的机制,对于编写高性能、无死锁的SQL至关重要。在实际应用中,我们经常会遇到因为间隙锁导致的并发问题,比如死锁或者事务长时间等待。

  1. 何时触发间隙锁?

    • REPEATABLE READ
      隔离级别下。
    • 当执行范围查询(
      WHERE col > X AND col < Y
      WHERE col LIKE 'prefix%'
      等)时。
    • 当对非唯一索引进行等值查询,且查询条件命中了多个记录,或者没有命中任何记录时,也会产生间隙锁。比如
      SELECT * FROM users WHERE status = 'pending' FOR UPDATE;
      如果
      status
      是非唯一索引,并且有很多
      pending
      的记录,那么这些记录以及它们之间的间隙都会被锁定。
    • INSERT
      操作在某些情况下也会产生间隙锁,例如在插入新记录时,为了检查唯一性约束,可能会锁定插入位置附近的间隙。
  2. 优化策略:

    • 考虑隔离级别: 如果你的业务场景能够接受较低的隔离级别(例如
      READ COMMITTED
      ),并且幻读不是一个核心问题,那么切换到
      READ COMMITTED
      可以完全禁用间隙锁(但仍会保留行锁)。这能显著提高并发性,但需要权衡数据一致性风险。
    • 精准索引设计: 确保你的查询能够尽可能地利用索引,并且查询条件能够精确匹配索引,避免全表扫描或大范围的索引扫描。对于唯一索引的等值查询,InnoDB只会加行锁,不会有间隙锁。
    • 缩小事务范围: 尽量让事务简短,减少锁持有的时间。长时间运行的事务,尤其是涉及范围查询的,会长时间持有间隙锁,极大地影响并发。
    • 避免不必要的锁定: 只有在确实需要防止幻读或数据不一致时,才使用
      FOR UPDATE
      LOCK IN SHARE MODE
    • 监控锁情况: 使用
      SHOW ENGINE INNODB STATUS
      可以查看当前的锁等待和死锁信息,帮助我们定位和分析间隙锁引起的问题。通过分析
      LATEST DETECTED DEADLOCK
      部分,我们可以看到是哪些事务、哪些SQL语句因为间隙锁而发生了死锁。
    • 批量操作: 对于需要更新或删除大量数据的操作,考虑分批处理,每次处理一小部分数据,可以减少单次事务持有间隙锁的时间和范围。

间隙锁是一个强大的工具,它在保证数据一致性方面功不可没,但同时它也是一把双刃剑,不恰当的使用或不理解其工作原理,很容易导致性能瓶颈。所以,深入理解它,并结合业务场景进行优化,是我们每个开发者都需要掌握的技能。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

682

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

320

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

347

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1095

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

357

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

676

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

575

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

417

2024.04.29

微信聊天记录删除恢复导出教程汇总
微信聊天记录删除恢复导出教程汇总

本专题整合了微信聊天记录相关教程大全,阅读专题下面的文章了解更多详细内容。

36

2026.01.18

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.8万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 801人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号