Skip to content

概念卡片:MySQL 事务与 MVCC

一句话机制

事务隔离靠 MVCC(多版本并发控制):每条记录更新时都留 undo log 回滚日志,不同事务启动时创建不同的 Read View(一致性视图),读时用「当前值 + 回滚日志」倒推出自己该看到的旧版本。 这就是「同一条记录在系统里有多个版本」。

四种隔离级别

隔离级别现象视图机制
读未提交 RU别人没提交我也能看到无视图,直接读最新值
读已提交 RC别人提交了我才看到每条 SQL 执行时建视图
可重复读 RR(默认)事务期间看到的一直一致事务启动时建视图
串行化 Serial读写全加锁排队加锁,无并发

经典例子(值 1 → 事务 B 改成 2)

隔离级别V1(B 改后)V2(B 提交后)V3
读未提交222
读已提交122
可重复读112
串行化112

MVCC 实现原理

当前值 4 ←── undo log 链条:3 ← 2 ← 1
         (每个版本通过回滚操作可倒推回前一个状态)
  • undo log:每次更新记录一条回滚操作
  • Read View:事务启动时创建的一致性视图
  • 多版本:视图 A/B/C 里同一条记录的值分别是 1/2/4

Read View 何时建是 RC 和 RR 的核心区别:RR 事务启动时建(全程一致),RC 每条 SQL 建(能看到别的事务提交)。

长事务的危害

长事务 = 系统里有很老的 Read View,它可能用到的回滚日志都不能删 → 存储膨胀(旧版 ibdata 无限涨)+ 长占锁资源。

sql
-- 查持续时间 > 60s 的事务
SELECT * FROM information_schema.innodb_trx
WHERE TIME_TO_SEC(timediff(now(), trx_started)) > 60;

事务启动最佳实践

  • set autocommit=0:关闭自动提交,select 也会开启事务且不提交 → 易产生长事务
  • set autocommit=1 + 显式 begin/commit
  • commit work and chain:提交当前事务并立即开新事务(省一次 begin,继承隔离级别)

常见误解(避坑)

  1. ❌ "可重复读是「只读不写」"。→ 是「事务期间读到的数据前后一致」,与是否写无关。
  2. ❌ "RC 和 RR 只是视图创建时机不同,没别的差"。→ 这正是幻读能否解决的关键:RR 下 InnoDB 用 next-key lock 结合 MVCC 解决幻读。
  3. ❌ "长事务只是占连接"。→ 核心危害是回滚日志无法清理导致磁盘膨胀,还会占锁。
  4. ❌ "MVCC 靠锁实现隔离"。→ MVCC 是无锁的快照读(不加锁),读写不互斥;锁用于当前读。

关联

最近更新