锁和隔离级别的关系

1. 表锁 (Table Lock)

  • 与隔离级别的关系基本无关
  • 说明:表锁是MySQL中最基本的锁策略,它直接锁住整张表。它的行为(如读锁、写锁)主要由SQL语句本身决定(例如 LOCK TABLES ... READ/WRITE 或某些DDL语句如 ALTER TABLE),与您设置的事务隔离级别(Read Uncommitted, Read Committed, Repeatable Read, Serializable)没有直接关系。它是一种独立存在的锁机制。

2. 行级锁 (Row-Level Locks)

行级锁是InnoDB引擎的精髓,其行为与隔离级别密切相关

InnoDB的行级锁包含三种算法:

  • 记录锁 (Record Lock):锁住索引上的一条具体记录。
  • 间隙锁 (Gap Lock):锁住一个索引区间,但不包括记录本身。
  • 临键锁 (Next-Key Lock)记录锁 + 间隙锁 的组合,锁住一个记录及其之前的间隙。这是InnoDB在RR隔离级别下默认的加锁算法。

现在我们来分析它们与隔离级别的关系:

a. 记录锁 (Record Lock)

  • 在所有隔离级别下都存在
  • 说明:当你更新、删除一条确切存在的记录,或者使用 SELECT ... FOR UPDATE/SELECT ... FOR SHARE 显式锁定时,InnoDB都会给该记录加上记录锁,防止其他事务修改它。这是保证事务“写操作”隔离性的基础,所以在所有隔离级别下都需要。

b. 间隙锁 (Gap Lock) 和 临键锁 (Next-Key Lock)

  • 与隔离级别强相关
  • 说明
    • 读已提交 (Read Committed, RC)读未提交 (Read Uncommitted, RU) 隔离级别下,InnoDB不会使用间隙锁或临键锁。它只使用记录锁。因此,在RC级别下,可能会发生“幻读”(Phantom Read)。
    • 可重复读 (Repeatable Read, RR)串行化 (Serializable) 隔离级别下,InnoDB会使用间隙锁和临键锁。这是为了防止“幻读”现象。临键锁默认锁住一个左开右闭的区间,它不仅能防止其他事务在区间内插入新记录(解决幻读),也能防止修改或删除区间内已有的记录。

总结与对比

锁类型 / 隔离级别 RU / RC (读未提交/读已提交) RR / Serializable (可重复读/串行化)
记录锁 (Record Lock)
间隙锁 (Gap Lock) (用于防止幻读)
临键锁 (Next-Key Lock) (默认行锁算法)
表锁 (但由特定语句触发,与隔离级别无关) (但由特定语句触发,与隔离级别无关)

举例说明

假设有一张表 users,其 id 为主键,数据有:1, 5, 10。

  • 场景:在 WHERE id = 7 的条件下进行更新7 是一条不存在的记录)。
    • 在 RC 级别
      • 因为 7 不存在,所以没有记录可加记录锁
      • 因为没有间隙锁,所以这个查询不会锁定任何东西(或者最多加一个轻量的“谓词锁”但很快释放)。其他事务可以自由地插入 id=7 的新记录。
    • 在 RR 级别
      • 虽然 7 不存在,但为了防止幻读(防止其他事务插入 id=7 的记录),InnoDB会使用间隙锁,锁住 (5, 10) 这个区间。
      • 其他事务如果试图在这个区间内插入任何值(如6, 7, 8)都会被阻塞,直到当前事务提交或回滚。

结论

  1. 表锁的存在与隔离级别无关。
  2. 记录锁 (Record Lock) 在所有隔离级别下都存在,是行级锁的基础。
  3. 间隙锁 (Gap Lock)临键锁 (Next-Key Lock)InnoDB 在 RR (可重复读) 及以上隔离级别中用于解决幻读问题的关键工具,在 RC 及以下隔离级别中不会被使用。

在较低隔离级别下,“行锁”仅指“记录锁”,而不包含“间隙锁”和“临键锁”这些更复杂的锁类型。锁机制和隔离级别是协同工作的,共同决定了数据库的并发行为和一致性保证。

posted @ 2025-08-30 16:40  adragon  阅读(7)  评论(0)    收藏  举报