MySQL 事务核心机制(ACID + 隔离 + 2PC)

mysql 📚 learning mysql-transaction-core · acid · transaction · isolation · 2pc · wal · binlog · redo-log · undo-log

TL;DR(30 秒扫完)

  • ACID 四个字母,前三个(A/I/D)由数据库保证,C 靠数据库+业务一起保证
  • 三个日志 各司其职:undo 记旧值做回滚、redo 记物理页做崩溃恢复、binlog 记逻辑操作做复制
  • 隔离级别 靠 MVCC + 锁配合实现,MySQL 默认 RR,互联网公司常切 RC
  • 2PC 是保证 redo 和 binlog 一致的协议,三阶段:redo prepare → 写 binlog → redo commit
  • 一个事务的完整提交流程 = WAL 写 redo → 2PC 协调 → binlog 落盘 → InnoDB commit → 通知主线程

关键结论

结论 AACID 的 C 不是数据库单独提供的,是业务和数据库共同保证
结论 B持久性靠 redo log 的 WAL 机制,不是 binlog
结论 CMySQL 内部 2PC 的核心不变量是"binlog 是提交成功的标志"
结论 DMVCC 只用于快照读,当前读(SELECT FOR UPDATE / UPDATE / DELETE)不走 MVCC
结论 EMySQL 默认 RR 不是"性能优先",而是一致性优先的折中

完整讲解(费曼四步)

STEP 1 · 概念

MySQL 事务的核心是"让多个读写操作要么全部成功,要么全部回滚,且不干扰其他事务,且已提交的结果不丢"。这套机制由三块拼起来:日志层(undo/redo/binlog)+ 隔离机制(锁 + MVCC)+ 协调协议(2PC)。

STEP 2 · 大白话

图书馆比喻:
  • undo log 是"修改记录本"——每次改书前抄一份原文,出问题按记录本恢复
  • redo log 是"施工日志"——记着哪本书哪页要改成什么,崩溃后用日志重放
  • binlog 是"借阅流水"——记着每次操作是谁做的,供另一个图书馆(从库)照抄
  • 2PC 是"图书馆经理和分馆的确认流程"——总馆说"改好了",分馆说"记好了",两边都对上才算真完成

STEP 3 · 底层

三个日志的分工

日志层级记录内容主要用途
undo logInnoDB 引擎层旧值(逻辑)回滚 + MVCC
redo logInnoDB 引擎层物理页修改崩溃恢复(WAL)
binlogMySQL Server 层逻辑 SQL / row主从复制 + 灾备

ACID 每个字母对应机制

字母含义核心机制
A原子性undo log(回滚)
C一致性约束 + 业务代码 + 前三性
I隔离性锁(行锁/间隙锁)+ MVCC
D持久性redo log + 2PC

隔离级别谱系

RU → RC → RR → Serializable
      ↑       ↑
  Oracle  默认
  默认    MySQL 默认
  • RC:每次 SELECT 新建 ReadView,只有行锁,无间隙锁
  • RR:事务首次 SELECT 生成一次 ReadView,next-key lock

MySQL 2PC 三阶段

Phase 1: redo prepare(不 commit)
Phase 2: 写 binlog 到磁盘
Phase 3: redo commit
崩溃恢复判断表:
redo 状态binlog 状态处理
prepare未写回滚
prepare已写提交
commit已写已完成,重放

关键参数

innodb_flush_log_at_trx_commit = 1    # 每次 commit 刷 redo(最安全)
sync_binlog                     = 1    # 每次刷 binlog
innodb_deadlock_detect          = ON   # 自动死锁检测
innodb_lock_wait_timeout        = 50   # 锁等待超时(秒)

STEP 4 · 简化

一句话总结:ACID 靠三日志撑起来——A 靠 undo、D 靠 redo + 2PC、I 靠锁+MVCC、C 靠业务。binlog 是复制用的,不是持久性用的,这是最容易混的点。 记忆口诀:
  • 日志三兄弟:undo 撤销 · redo 重做 · binlog 复制
  • 2PC 三阶段:prepare · binlog · commit
  • 隔离级别:RC 每次新 ReadView,RR 只生成一次

常见误区

把 undo log 说成"重做日志"
undo = 撤销,redo = 重做
说"binlog 保证持久性"
持久性靠 redo log(WAL),binlog 只负责复制
说"MySQL 2PC 是先写日志再批量提交到磁盘"
那是组提交,不是 2PC
说"RR 是为了性能优先"
RR 是一致性优先的折中,RC 才更省锁
说"MVCC 用于所有读"
MVCC 只用于快照读,当前读走锁
ACID 的 I 答成"可用性"
I = Isolation(隔离性)

延伸追问

redo log 和 binlog 都是"日志",为什么不能只用一个?
redo 是引擎层物理日志,服务崩溃恢复;binlog 是 Server 层逻辑日志,服务复制。分工不同,缺一不可。
2PC 崩溃后如何决定提交还是回滚?
看 redo 状态和 binlog 状态:binlog 未写则回滚,binlog 已写则提交。
innodb_flush_log_at_trx_commit=2 什么时候用?
MySQL 崩溃不丢(已写 OS cache),系统崩溃可能丢。适合日志量大、可容忍系统崩溃丢数据的场景。
为什么很多互联网公司切 RC?
RR 的间隙锁死锁多、锁等待长;RC 锁粒度小并发高。

速查表

ACID: A→undo / C→业务 / I→锁+MVCC / D→redo+2PC
日志: undo撤销 · redo重做 · binlog复制
2PC:  prepare → binlog → commit
崩溃: 无binlog→回滚 / 有binlog→提交
RR: 一次 ReadView · 有间隙锁
RC: 每次 ReadView · 无间隙锁
双1: sync_binlog=1 + innodb_flush_log_at_trx_commit=1

Anki 候选卡片

Q: ACID 每个字母对应什么机制?
A: A→undo / C→业务+约束 / I→锁+MVCC / D→redo+2PC
Q: undo log 和 redo log 分别做什么?
A: undo 记旧值做回滚和 MVCC;redo 记物理页修改做崩溃恢复
Q: binlog 的主要用途?
A: 主从复制 + 灾备,不是持久性保证
Q: 2PC 三阶段是什么?
A: redo prepare → 写 binlog → redo commit
Q: 2PC 崩溃恢复判断逻辑?
A: binlog 未写→回滚;binlog 已写→提交
Q: RC 和 RR 在 ReadView 上的差异?
A: RC 每次 SELECT 新建;RR 事务首次 SELECT 生成一次
Q: MVCC 用于哪种读?
A: 快照读;当前读(SELECT FOR UPDATE / UPDATE / DELETE)走锁
Q: MySQL 默认 RR 的原因?
A: 一致性优先的折中——MVCC 让 RR 快照读不加锁,性能仍高

关联题目

  • ⚠️ 《什么是事务的 ACID 特性》— Round 1 Q1, ⭐⭐(I 答成可用性)
  • ⚠️ 《MySQL 事务 ACID 是如何实现的?》— Round 2 B2, ⭐⭐(undo/redo 混淆)
  • ⚠️ 《MySQL 中的事务隔离级别?》— Round 2 B1, ⭐⭐⭐(RC/RR 边界)
  • ⚠️ 《为什么 MySQL 默认使用 RR 隔离级别?》— Round 2 B4, ⭐(方向反了)
  • ⚠️ 《什么是事务的 2 阶段提交?》— Round 2 B5, ⭐⭐(混淆组提交)
  • ⚠️ 《介绍下 MySQL 5.7 中的组提交?》— Round 1 Q8, ⭐⭐(术语错误)

关联知识

ACID 靠三日志(redo/undo/binlog)+ MVCC+锁 + 2PC 撑起来
图书馆:undo 是修改记录本,redo 是施工日志,binlog 是借阅流水
✦ 记 忆 口 诀 ✦
日志三兄弟:undo 撤销 · redo 重做 · binlog 复制
关键可视化
ACID 每个字母对应机制
flowchart TB
  A["ACID 四大特性"]
  A --> A1["A 原子性"]
  A --> C1["C 一致性"]
  A --> I1["I 隔离性"]
  A --> D1["D 持久性"]
  A1 --> A2["undo log 回滚"]
  C1 --> C2["约束 + 业务代码"]
  I1 --> I2["锁 + MVCC"]
  D1 --> D2["redo log + 2PC"]
MySQL 内部 2PC 三阶段
flowchart LR
  S["事务开始"] --> P1["Phase 1: redo prepare"]
  P1 --> P2["Phase 2: 写 binlog"]
  P2 --> P3["Phase 3: redo commit"]
  P3 --> E["事务提交完成"]
  P1 -->|崩溃| C1["判断 binlog 是否已写"]
  P2 -->|崩溃| C1
  C1 -->|未写| R["回滚"]
  C1 -->|已写| T["提交"]
隔离级别谱系
flowchart LR
  RU["RU"] --> RC["RC<br/>每次新 ReadView"]
  RC --> RR["RR<br/>首次 ReadView<br/>默认"]
  RR --> SER["Serializable"]
费曼式可视化(完整图解)
↗ 新窗口打开
知识关系

⬆️ 前置(Prerequisite)

暂无

🔄 延伸(Extends)

mvcc

⚡ 对比(Contrast)

MVCC 快照读— MVCC 是 ACID 中 'I 隔离性' 的实现方案之一redo vs undo log— 最容易混:redo=重做物理页;undo=撤销旧值;两者不同层级
🎯 概念 📏 规则 ⚠️ 误区 🔍 追问 ✨ 口诀 共 0 张卡,点击翻面