web学习笔记编程技术学习与分享

事务隔离级别与幻读

2026 年 08 月 26 日约 3 分钟阅读 后端与数据库

并发事务会出现三类经典问题:脏读(读到未提交数据)、不可重复读(两次读到的值不同)、幻读(两次读到的行数不同)。四个隔离级别就是逐步收紧这三类问题的方案。

四个级别

级别 脏读 不可重复读 幻读
READ UNCOMMITTED 可能 可能 可能
READ COMMITTED 不会 可能 可能
REPEATABLE READ(InnoDB 默认) 不会 不会 基本不会
SERIALIZABLE 不会 不会 不会

InnoDB 如何做到「基本不会」

InnoDB 在 REPEATABLE READ 下靠两套机制:

MVCC(快照读):普通 SELECT 读的是事务开始时的快照。其他事务新插入的行,因创建版本号更新,当前事务看不到——幻读在快照读里被消除了。

间隙锁(当前读):SELECT ... FOR UPDATE 这类锁定读会锁住已有记录之间的间隙,阻止其他事务在范围内插入。

但两者边界容易被忽略:

-- 事务 A(RR 级别)
SELECT * FROM t WHERE id > 10;          -- 快照读,看到 N 行
SELECT * FROM t WHERE id > 10 FOR UPDATE;  -- 当前读,能看到新提交的行

第一次是快照,第二次是当前读,两者结果可以不一致。同一个事务里混用两种读,就绕过了 MVCC 的保护。

实践建议

  • 需要严格一致的「读后写」场景,统一用当前读(FOR UPDATE),不要先普通 SELECT 再写;
  • UPDATE/DELETE 本身是当前读,条件里的判断要与快照读分开对待;
  • 隔离级别保持默认 RR 即可,RC 在云数据库场景有它的优势,但需要清楚放弃了什么。

一个常被问到的问题

RR 下死锁变多怎么办?多数死锁源于「不同顺序加锁」。约定统一按主键顺序更新,并把事务控制在最小范围,能解决大部分死锁。SHOW ENGINE INNODB STATUS 的 LATEST DETECTED DEADLOCK 段是排查起点。

MySQL事务并发