Skip to content

where id > 10 会加锁吗?什么锁?id > 20 的记录会不会被锁

约 858 字大约 3 分钟

MySQL字节

2025-03-20

⭐ 题目日期:

字节 - 2024/12/17

📝 题解:

在 MySQL 的 可重复读(Repeatable Read) 隔离级别下,执行 WHERE id > 10 的查询时,是否会加锁以及具体锁的范围,取决于查询是否显式加锁。以下是详细分析:


1. 不加锁的普通查询

如果只是普通查询(如 SELECT * FROM table WHERE id > 10),不会加任何锁。此时:

  • 其他事务可以自由插入、修改或删除 id > 10 的记录。
  • 幻读可能发生:若其他事务插入 id > 10 的新记录,当前事务再次查询时会出现幻读。

2. 显式加锁的查询

如果通过 FOR UPDATELOCK IN SHARE MODE 显式加锁(如 SELECT * FROM table WHERE id > 10 FOR UPDATE),InnoDB 会通过 Next-Key Locks 锁定范围。具体锁行为如下:

2.1 加的锁类型

  • Next-Key Lock:行锁(Record Lock) + 间隙锁(Gap Lock)。
  • 锁范围:锁定所有满足 id > 10现有记录间隙(包括未来可能插入的 id > 10 的记录)。

2.2 锁的覆盖范围

假设表中现有记录为 id = 5, 15, 25,则:

  • 锁定记录id = 15, 25(行锁)。
  • 锁定间隙
    • (5, 15):现有记录之间的间隙。
    • (15, 25):现有记录之间的间隙。
    • (25, +∞):最大记录后的间隙。
  • 结论:所有 id > 10 的记录(如 id = 15, 25)及间隙均被锁定,id > 20 的记录(如 25)也会被锁定。

3. 示例验证

事务 A(加锁方)

BEGIN;
-- 显式加锁,锁定 id > 10 的范围
SELECT * FROM users WHERE id > 10 FOR UPDATE;

事务 B(尝试操作)

  • 插入 id = 12:被阻塞(间隙 (10, 15) 被锁定)。
  • 插入 id = 30:被阻塞(间隙 (25, +∞) 被锁定)。
  • 修改 id = 15:被阻塞(行锁)。
  • 结论:所有 id > 10 的操作均被阻塞,直到事务 A 提交。

4. 锁的底层原理

Next-Key Lock 的作用

  • 行锁(Record Lock):锁定已存在的记录(如 id = 15, 25)。
  • 间隙锁(Gap Lock):锁定索引范围之间的间隙(如 (5, 15)(15, 25)(25, +∞))。
  • 组合效果:禁止其他事务在锁定范围内插入或修改数据。

锁的兼容性

  • 排他锁(X Lock)FOR UPDATE 加的锁是排他锁,完全禁止其他事务读写。
  • 共享锁(S Lock)LOCK IN SHARE MODE 加的锁是共享锁,允许其他事务读但禁止写。

5. 关键结论

问题答案
WHERE id > 10 是否会加锁?普通查询不加锁;显式加锁(如 FOR UPDATE)会加 Next-Key Lock
加的什么锁?Next-Key Lock(行锁 + 间隙锁)。
id > 20 的记录是否被锁?是,所有 id > 10 的现有记录及间隙均被锁定,包括 id > 20 的记录。

6. 注意事项

  1. 索引依赖
    • Next-Key Lock 依赖索引,若 id 无索引,会退化为 表锁,严重影响性能。
  2. 死锁风险
    • 多个事务按不同顺序加锁可能导致死锁(如事务 A 锁定 id > 10,事务 B 锁定 id > 20)。
  3. 性能权衡
    • 范围锁会降低并发性能,需根据业务需求决定是否显式加锁。

总结

  • WHERE id > 10 的显式加锁查询会锁定所有 id > 10 的现有记录及间隙,包括 id > 20 的记录。
  • 通过 Next-Key Lock 机制,MySQL 在可重复读隔离级别下有效防止幻读,但需谨慎使用以避免性能问题。