You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL中BETWEEN查询加FOR UPDATE为何会在5之后产生间隙锁?

为什么范围加锁后,超出条件的A=6也被阻塞?

问题还原

表结构与初始数据

CREATE TABLE justpk
(
    A INT,
    B INT,
    PRIMARY KEY (A)
);

INSERT INTO justpk (A, B) VALUES (1, 1), (4, 1), (5, 1);

查询结果:

+---+------+
| a | b    |
+---+------+
| 1 |    1 |
| 4 |    1 |
| 5 |    1 |
+---+------+

会话操作

会话1执行加锁查询:

begin;
SELECT * FROM justpk WHERE A BETWEEN 1 AND 5 FOR UPDATE;

另一个会话的操作结果:

  • INSERT INTO lockingreads.justpk (A, B) VALUES (0, 1); → 正常执行
  • UPDATE lockingreads.justpk SET B = 2 WHERE A = 1; → 被阻塞
  • INSERT INTO lockingreads.justpk (A, B) VALUES (2, 1); → 被阻塞
  • INSERT INTO lockingreads.justpk (A, B) VALUES (3, 1); → 被阻塞
  • UPDATE lockingreads.justpk SET B = 2 WHERE A = 4; → 被阻塞
  • UPDATE lockingreads.justpk SET B = 2 WHERE A = 5; → 被阻塞
  • INSERT INTO lockingreads.justpk (A, B) VALUES (6, 1); → 被阻塞(疑问:A=6不在1-5范围内,为何被锁?)

原因解析

这是InnoDB在可重复读(RR)隔离级别下的**临键锁(Next-Key Lock)**特性导致的,核心是为了避免幻读:

  1. 临键锁的本质:临键锁是行锁+间隙锁的组合,当你用范围条件(比如BETWEEN、>、<)执行加锁查询时,InnoDB不仅会锁住符合条件的行,还会锁住这些行之间的间隙,以及最后一个匹配行之后到下一个主键值之间的间隙。
  2. 为什么A=6被锁?:你的表中最后一个匹配行是A=5,而表中没有比5更大的主键值,所以InnoDB会把间隙锁延伸到(5, +∞)的范围——也就是所有大于5的主键值都无法插入。这是因为InnoDB要确保在会话1的事务结束前,不会有新行插入到这个“末尾间隙”中,彻底杜绝幻读的可能。
  3. 为什么A=0可以插入?:第一个匹配行是A=1,但你的查询条件是A >=1,InnoDB不会对(-∞,1)的间隙加锁,因为这个区间的行根本不满足查询条件,插入A=0不会影响会话1的查询结果,所以允许执行。

简单说:RR级别下,范围加锁会锁到最后一个匹配行的“后面所有空位”,哪怕这些空位超出了你写的查询范围,目的就是防止新行插进来搞出幻读。

内容的提问来源于stack exchange,提问作者user19481364

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 00:40:19