事务(ACID → MySQL 内部是怎么实现的)

我用一句话总结:

A、C、I、D 不是分开的,它们是 InnoDB 内部六大模块协同“跑出来”的效果。

下面我按“工程师视角”讲每一项在 MySQL 内部到底怎么实现的。


🧱 0. ACID 一句话工程版总结

字母 真正含义(工程师视角) InnoDB 具体实现方式
A(原子性) 要么都成功,要么都失败 Undo Log + 回滚机制
C(一致性) 事务前后数据约束必须满足 依赖开发者 + ACID 联合保证
I(隔离性) 不同事务互不干扰 锁(行锁/间隙锁) + MVCC
D(持久性) 提交就不能丢 Redo Log + WAL + Double Write

1️⃣ A:原子性(Atomicity)—— Undo Log 实现的

工程视角就是一句话:

原子性 = 有撤销日志(Undo Log)→ 哪个 update 失败,就能按日志倒回去。

🧩 Undo Log 里有什么?

例如:

update user set age = 20 where id = 1;

Undo Log 会记录:

(表名 user, 主键 1, 修改前 age = 18)

如果事务失败,直接按 Undo Log 把数据恢复成 18。

🛠️ Undo Log 存在哪?

  • 存在 Undo 页(Undo Page)
  • Rollback Segment 管理
  • 是一条链(所谓 Undo 链)

💡 原子性在 MySQL 内部就一句话:

Undo Log 是“反向补丁(reverse patch)”。

写成功前提:事务还没 commit,随便回滚 → A 实现。


2️⃣ C:一致性(Consistency)—— ACID 联合作用 + 开发者保证

一致性不是 MySQL 单独保证的,它是一个最终结果:

你写的数据必须满足表结构约束(not null、unique、外键)与业务约束。

实现手段:

机制 保证什么一致性
原子性(Undo) 更新失败不会只更新一半
隔离性(MVCC/锁) 不被其他事务插手
持久性(Redo) crash 之后恢复一致
外键、唯一约束 保证业务结构不乱

一致性依赖 ACID ALL,而不是某一个模块。

所以 C 是效果,不是一个独立组件。


3️⃣ I:隔离性(Isolation)—— 锁 + MVCC 实现的

这块你已经理解不少,但我给你用工程师视角浓缩句:

隔离性 = 读靠 MVCC,写靠锁。
避免互相干扰靠 next-key lock。

🔧 写操作:InnoDB 使用行锁体系

  • 行锁(Record Lock)
  • 间隙锁(Gap Lock)
  • Next-Key Lock(Record + Gap)

实现方式:事务写行时加锁,别人不能改。


🔍 读操作:RC / RR 靠 MVCC

MVCC 用三样东西:

  1. undo log(历史版本)
  2. trx_id(每行都有版本号)
  3. read view(事务可见性判断)

RR / RC 的区别:

隔离级别 读取版本策略
RC 每次读都重新生成 ReadView
RR 一个事务内共享同一个 ReadView

一句话:

RR 读取的是“事务开始时的快照”,RC 读取的是“最新快照”。

因此没有幻读靠锁,而不是 MVCC。


4️⃣ D:持久性(Durability)—— Redo Log + WAL

核心机制一句话:

持久性不是靠把数据写入磁盘页,而是靠 Redo Log。
数据页可以慢写,但 redo 必须先落盘。
这就是 WAL:Write-Ahead Logging。


🔥 MySQL 持久性流程全图(极简工程师版)

事务执行:

update ...

流程:

  1. Buffer Pool 中修改页(脏页)
  2. 生成 Redo 日志(物理日志)
  3. Redo Log 先写到磁盘(顺序写,非常快)
  4. 客户端收到“提交成功”
  5. 后台慢慢把脏页(data page)Flush 到磁盘

也就是说:

👉 提交成功 ≠ 数据页落盘
👉 提交成功 = redo log 已落盘

Crash 后,根据 Redo Log 恢复一致状态 → D 实现。


⭐ ACID = 6 个核心组件一起跑出来的

ACID 内部实现核心
A Undo Log
C Undo + Redo + MVCC + 锁
I 锁 + MVCC
D Redo Log + WAL + DoubleWrite

🔥 重点来了:ACID 四个特性不是分开工作的

它们不是线性的,而是像“组件树”一样协作:

事务开始
│
├── 修改 Buffer Pool
├── 写 Undo Log(为了原子性、MVCC)
├── 写 Redo Log(为了持久性)
├── 加锁(为了隔离性)
│
└── 提交 → 决定读写可见性

Undo 与 Lock 共同做隔离性
Undo 与 ReadView 共同做 MVCC
Redo 单独负责持久性
最终共同保证一致性

这就是 InnoDB 的 ACID。

posted @ 2025-12-06 14:51  中登程序猿  阅读(0)  评论(0)    收藏  举报