📢 欢迎来到万事技术论坛!本站仅讨论合法编程技术话题,严禁外挂/作弊/黑产/盗版内容,违者封号。

精华事务隔离级别:可重复读真的能防住幻读吗

dba_zhou 进阶会员

一张表先说清四个级别(MySQL InnoDB):

级别 脏读 不可重复读 幻读
读未提交 会 会 会
读已提交 RC 不会 会 会
可重复读 RR(默认) 不会 不会 基本不会
串行化 不会 不会 不会

三个概念

  • 脏读:读到别人没提交的数据
  • 不可重复读:同一行两次读,值变了(别人改了并提交)
  • 幻读:同样的条件两次查,行数变了(别人插入了新行)

区别在于:不可重复读针对已存在的行被修改,幻读针对新增的行。

RR 为什么能防住大部分幻读

两个机制配合:

  1. MVCC 快照读:普通 SELECT 读的是事务开始时的快照,别人插入的新行对你不可见;
  2. 间隙锁(Gap Lock):SELECT ... FOR UPDATE 这类当前读会锁住索引记录之间的间隙,别人插不进来。

但有一个经典例外

快照读和当前读混用会出问题:

-- 事务 A
BEGIN;
SELECT * FROM t WHERE id > 100;      -- 快照读,看到 3 行
-- 此时事务 B 插入 id=200 并提交
SELECT * FROM t WHERE id > 100 FOR UPDATE;   -- 当前读,看到 4 行!
COMMIT;

同一个事务里两次查询行数不一致——这就是 RR 下依然可能出现的幻读。原因是当前读会读到最新提交版本,绕过快照。

规避:事务里一旦要用 FOR UPDATE / UPDATE,从头就用当前读,别混。

RC 和 RR 怎么选

RC RR
锁范围 小,无间隙锁 大,有间隙锁
并发度 高 低
死锁概率 低 高
主从复制 需 binlog 用 ROW 格式 都行

互联网高并发业务(尤其有大量 UPDATE ... WHERE 的)我倾向改 RC,死锁少很多,靠业务侧乐观锁解决一致性。

查看当前级别:SELECT @@transaction_isolation;

楼主 · 2026-09-28 13:21 · 浏览 2
ops_wang 进阶会员

长事务那个真的要强调:我们有个定时任务开了事务又去调外部 HTTP,
接口慢的时候锁住了几万行,整个库卡死。现在规定事务里一律不做外部调用。

1楼 · 2026-09-28 14:31
登录 后即可参与回复。