---
title: MySQL 事务核心机制（ACID + 隔离 + 2PC）
type: concept
domain: mysql
tags: [acid, transaction, isolation, 2pc, wal, binlog, redo-log, undo-log]
status: learning
created: 2026-09-17
last_reviewed: 2026-09-17
method: feynman
related_questions:
  - "什么是事务的ACID特性"
  - "MySQL事务ACID是如何实现的？"
  - "MySQL中的事务隔离级别？"
  - "为什么MySQL默认使用RR隔离级别？"
  - "什么是事务的2阶段提交？"
related_knowledge:
  - ./mvcc.md
visualizations:
  - ./mysql-acid-mvcc-feynman.html
anki_cards: 8
interview_rounds:
  - "2026-09-17-round-1-Q1"
  - "2026-09-17-round-1-Q8"
  - "2026-09-17-round-2-B1"
  - "2026-09-17-round-2-B2"
  - "2026-09-17-round-2-B4"
  - "2026-09-17-round-2-B5"
---

# MySQL 事务核心机制（ACID + 隔离 + 2PC）

> 面试里最容易答错的高频考点集合。这一份是"元知识文档"——把三大块（ACID、隔离级别、2PC）串成一个整体故事。

## 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 → 通知主线程

## 关键结论

- **结论 A**：ACID 的 C 不是数据库单独提供的，是业务和数据库共同保证
- **结论 B**：持久性靠 redo log 的 WAL 机制，**不是** binlog
- **结论 C**：MySQL 内部 2PC 的核心不变量是"binlog 是提交成功的标志"
- **结论 D**：MVCC 只用于快照读，当前读（SELECT FOR UPDATE / UPDATE / DELETE）不走 MVCC
- **结论 E**：MySQL 默认 RR 不是"性能优先"，而是**一致性优先的折中**

## 完整讲解（费曼四步）

### STEP 1 · 概念

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

### STEP 2 · 大白话

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

### STEP 3 · 底层

#### 三个日志的分工

| 日志 | 层级 | 记录内容 | 主要用途 |
|------|------|---------|---------|
| **undo log** | InnoDB 引擎层 | 旧值（逻辑） | 回滚 + MVCC |
| **redo log** | InnoDB 引擎层 | 物理页修改 | 崩溃恢复（WAL） |
| **binlog** | MySQL 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  | 已写 | 已完成，重放 |

#### 关键参数

```ini
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 只生成一次

## 常见误区

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

## 延伸追问

1. **redo log 和 binlog 都是"日志"，为什么不能只用一个？**
   - redo 是引擎层物理日志，服务崩溃恢复；binlog 是 Server 层逻辑日志，服务复制。分工不同，缺一不可。
2. **2PC 崩溃后如何决定提交还是回滚？**
   - 看 redo 状态和 binlog 状态：binlog 未写则回滚，binlog 已写则提交。
3. **`innodb_flush_log_at_trx_commit=2` 什么时候用？**
   - MySQL 崩溃不丢（已写 OS cache），系统崩溃可能丢。适合日志量大、可容忍系统崩溃丢数据的场景。
4. **为什么很多互联网公司切 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
```

## 关联题目（题库）

- ⚠️ 《什么是事务的 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, ⭐⭐（术语错误）

## 关联知识

- [MVCC 多版本并发控制](./mvcc.md)
- [主题地图](./_moc.md)

## Anki 候选卡片

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

---

*最后更新：2026-09-17*
