主题
概念卡片:MySQL 事务与 MVCC
一句话机制
事务隔离靠 MVCC(多版本并发控制):每条记录更新时都留 undo log 回滚日志,不同事务启动时创建不同的 Read View(一致性视图),读时用「当前值 + 回滚日志」倒推出自己该看到的旧版本。 这就是「同一条记录在系统里有多个版本」。
四种隔离级别
| 隔离级别 | 现象 | 视图机制 |
|---|---|---|
| 读未提交 RU | 别人没提交我也能看到 | 无视图,直接读最新值 |
| 读已提交 RC | 别人提交了我才看到 | 每条 SQL 执行时建视图 |
| 可重复读 RR(默认) | 事务期间看到的一直一致 | 事务启动时建视图 |
| 串行化 Serial | 读写全加锁排队 | 加锁,无并发 |
经典例子(值 1 → 事务 B 改成 2)
| 隔离级别 | V1(B 改后) | V2(B 提交后) | V3 |
|---|---|---|---|
| 读未提交 | 2 | 2 | 2 |
| 读已提交 | 1 | 2 | 2 |
| 可重复读 | 1 | 1 | 2 |
| 串行化 | 1 | 1 | 2 |
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,继承隔离级别)
常见误解(避坑)
- ❌ "可重复读是「只读不写」"。→ 是「事务期间读到的数据前后一致」,与是否写无关。
- ❌ "RC 和 RR 只是视图创建时机不同,没别的差"。→ 这正是幻读能否解决的关键:RR 下 InnoDB 用 next-key lock 结合 MVCC 解决幻读。
- ❌ "长事务只是占连接"。→ 核心危害是回滚日志无法清理导致磁盘膨胀,还会占锁。
- ❌ "MVCC 靠锁实现隔离"。→ MVCC 是无锁的快照读(不加锁),读写不互斥;锁用于当前读。
关联
- 原始资料:03_事务隔离:为什么你改了我还看不见?
- 总览:MySQL技术栈总览
- 相关卡:概念卡片:MySQL锁机制(MVCC 管快照读、锁管当前读,两者配合)
- 域地图:A00-百科/数据与存储/数据与存储