基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

InnoDB 的行锁有哪些类型?

在 MySQL 的 InnoDB 存储引擎中,行锁(Row-level Locks)是实现并发控制和事务隔离级别的核心机制。需要特别注意的是:InnoDB 的行锁是加在“索引”上的,而不是直接加在物理行记录上。 如果查询没有命中任何索引,行锁会退化为表锁(实际上是锁住了隐藏的聚簇索引的所有记录及间隙)。

根据锁的算法和作用范围,InnoDB 的行锁主要分为以下 4 种类型

1. 记录锁(Record Lock)

  • 定义:仅仅锁住单条索引记录
  • 作用范围:精确命中一条记录。
  • 触发场景:通常出现在使用唯一索引(包括主键)进行等值查询且命中记录时。
  • 示例
    sql
    -- 假设 id 是主键
    SELECT * FROM user WHERE id = 10 FOR UPDATE;
    此时,InnoDB 只会对 id = 10 的这一行索引记录加锁,阻止其他事务对其进行 UPDATEDELETE

2. 间隙锁(Gap Lock)

  • 定义:锁住索引记录之间的间隙(Gap),或者锁住第一条记录之前、最后一条记录之后的间隙。它不包含索引记录本身。
  • 作用范围:开区间 (A, B)
  • 核心目的:为了阻止其他事务在这个间隙内插入(INSERT)新的数据,从而防止幻读(Phantom Read)
  • 触发场景
    • 可重复读(Repeatable Read, RR) 隔离级别下生效。
    • 使用普通索引(非唯一索引)进行等值查询时。
    • 使用范围查询(如 BETWEEN<>)时。
  • 特性:间隙锁之间是不互斥的。事务 A 和事务 B 可以同时对同一个间隙加 Gap Lock。间隙锁唯一排斥的操作是“在间隙中插入新记录”。

3. 临键锁(Next-Key Lock)

  • 定义记录锁 + 间隙锁 的组合。它不仅锁住索引记录本身,还锁住该记录之前的那个间隙。
  • 作用范围:左开右闭区间 (A, B]
  • 触发场景Next-Key Lock 是 InnoDB 在可重复读(RR)隔离级别下的默认行锁算法。
  • 示例与锁降级
    假设表中有一个普通索引包含值:10, 20, 30。
    Next-Key Lock 可以划分的区间为:(-∞, 10], (10, 20], (20, 30], (30, +∞)
    • 当执行 SELECT * FROM table WHERE age = 20 FOR UPDATE; 时,会锁住 (10, 20] 区间,同时为了防止在 20 后面插入,还会加上 (20, 30) 的间隙锁。
    • 锁降级机制
      • 当查询的索引是唯一索引(或主键),且属于等值查询命中记录时,Next-Key Lock 会降级为记录锁(Record Lock)
      • 当等值查询未命中记录时,Next-Key Lock 会降级为间隙锁(Gap Lock)

4. 插入意向锁(Insert Intention Lock)

  • 定义:这是一种特殊的间隙锁。由 INSERT 操作在插入数据之前产生。
  • 核心目的:提高插入并发度。它表示一种插入的意向,即“我打算在这个间隙里插入一条数据”。
  • 特性
    • 互不排斥:如果多个事务向同一个间隙插入不同的数据,它们都会获取这个间隙的插入意向锁,但彼此之间不会阻塞。例如间隙是 (10, 20),事务 A 插入 15,事务 B 插入 16,两者都能顺利执行。
    • 被 Gap/Next-Key Lock 排斥:如果事务 A 对间隙 (10, 20) 加了普通的间隙锁或临键锁,那么事务 B 想要在这区间插入数据时获取“插入意向锁”就会被阻塞。

补充:行锁的模式(Lock Modes)

以上 4 种类型是基于“锁的范围/算法”划分的。从“读写排他性”来看,行锁又分为两种模式:

  1. 共享锁(Shared Lock,简称 S 锁 / 读锁)
    • 允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
    • 触发语句:SELECT ... LOCK IN SHARE MODE (MySQL 8.0 推荐 FOR SHARE)。
  2. 排他锁(Exclusive Lock,简称 X 锁 / 写锁)
    • 允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享锁和排他锁。
    • 触发语句:SELECT ... FOR UPDATEUPDATEDELETE

总结

InnoDB 通过 Record Lock 保障数据行不被并发修改,通过 Gap LockNext-Key Lock 解决可重复读级别下的“幻读”问题,并通过 Insert Intention Lock 保证了在防止幻读的同时兼顾了数据插入的并发性能。

00:00
00:00