news 2026/9/13 10:43:36

DDIA 导读(七):事务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DDIA 导读(七):事务

本文是《Designing Data-Intensive Applications》(DDIA,中文译名《数据密集型应用系统设计》)第 7 章的导读。DDIA 是 Martin Kleppmann 所著的分布式系统经典,本系列逐章导读,把书的核心概念讲清楚。

一句话主旨

事务是"把多个操作打包成一个原子单元"的抽象——要么全做,要么全不做。但"全做全不做"在并发和故障下要付出代价,而代价的大小取决于你选多强的隔离级别。本章的核心不是 ACID 的定义,而是隔离级别的谱系:从最弱的"读未提交"到最强的"可串行化",每一级挡掉一类并发异常,也付出一份性能代价。


核心概念拆解

1. ACID——四个保证,但 A 和 I 是重点

靠 undo log / WAL

靠锁/MVCC

靠 WAL + fsync

应用层约束

A 原子性
全做或全不做

C 一致性
不变量不被破坏

I 隔离性
并发如串行

D 持久性
提交了就不丢

回滚机制

并发控制

预写日志

应用保证

  • A 原子性:一组操作要么全成功要么全回滚。靠 undo log / WAL 实现。
  • C 一致性:数据的业务不变量(如"余额不为负")在事务后仍成立。C 是应用层责任,数据库提供 A/I/D 帮你达到 C,但 C 本身要应用定义。
  • I 隔离性:并发事务互不干扰,效果如同串行执行。这是本章主角——完整隔离(可串行化)代价高,所以有各级别。
  • D 持久性:事务提交后即使断电也不丢。靠 WAL + fsync。

A、I、D 是数据库机制,C 主要是应用责任。第 7 章几乎全在讲 I(隔离级别),因为 I 是性能与正确性权衡的主战场。

2. 隔离级别的谱系——每级挡一类异常

这是本章的重头。并发事务会互相干扰,产生各种"异常"(anomaly)。隔离级别从弱到强,每级挡掉一类异常,代价是性能下降。

挡脏读

挡不可重复读

挡幻读(部分)

挡写偏斜/完整

读未提交 Read Uncommitted
能读到别人未提交的(脏读)

读已提交 Read Committed
只读已提交的, 但同一行两次读可能不同(不可重复读)

可重复读 Repeatable Read
同一行多次读一致, 但范围查询可能多/少行(幻读)

快照隔离 Snapshot Isolation
读一个一致快照, 写写冲突靠乐观检测

可串行化 Serializable
完全等价于串行, 无任何异常

四种并发异常(从轻到重)

① 脏读(Dirty Read)——读到别人还没提交的数据。对方回滚了,你读的就成了"从未存在过的数据"。读未提交级别下发生,读已提交挡掉。

② 不可重复读(Non-repeatable Read)——同一事务里读同一行两次,值变了(别人提交了更新)。读已提交下发生,可重复读挡掉。

③ 幻读(Phantom Read)——同一事务里范围查询两次,结果集行数变了(别人提交了插入/删除)。可重复读挡行级读一致但挡不住范围新增,快照隔离挡掉。

④ 写偏斜(Write Skew)——两个事务各自读了一致快照,基于快照各自做决策并写入,两个写入合在一起违反了业务约束,但单独看都不违规。快照隔离挡不住这个,只有可串行化挡得住。

写偏斜是快照隔离的盲区,也是最难直觉理解的异常。经典例子:值班规则要求"至少一人值班",A 和 B 都在值班,两人同时申请休假——各自快照里看到"对方在值班,我走没关系",都提交休假,结果没人值班。单独看每个事务都合规,合起来违反约束。只有可串行化能防。

问题→方案:问题——并发操作互相干扰产生异常。场景——多个事务同时读写相同数据,弱隔离下出现脏读/不可重复读/幻读/写偏斜。方案——隔离级别谱系:每升一级挡掉一类异常,代价是性能下降。读已提交挡脏读,可重复读挡不可重复读,快照隔离靠 MVCC 让读写不互锁(读历史版本、写写冲突先到先赢),可串行化靠 2PL 或 SSI 挡写偏斜。选哪级 = 你能容忍哪种异常 vs 愿付多少性能代价。

3. 快照隔离(SI)——现代主流

事务2(开始于t=20)数据库(MVCC)事务1(开始于t=10)事务2(开始于t=20)数据库(MVCC)事务1(开始于t=10)快照隔离: 事务看到自己开始时刻的一致视图读X(看到t=10时的快照版本)写X=新值并提交再读X(仍看到t=10快照, 不受T2影响)

核心机制——MVCC(多版本并发控制)

  • 每行数据有多个版本(带时间戳/事务号)
  • 事务开始时"拍一个快照"——只看开始时刻已提交的版本
  • 读不阻塞写,写不阻塞读(各看各版本)——读写不互锁,这是 SI 高性能的关键
  • 写写冲突检测:两个事务同时改同一行,后提交的被检测到冲突并回滚(first-committer-wins)

大多数现代 OLAP/HTAP 系统都用 MVCC + 快照隔离。分析负载以读为主,弱隔离够用且快得多。

4. 乐观锁 vs 悲观锁——两种并发控制思路

乐观锁 (Optimistic)

无冲突

有冲突

读+改(不加锁)

提交时检测冲突?

提交成功

回滚重试

悲观锁 (Pessimistic)

先加锁

改数据

提交/释放锁

悲观锁:先锁再改。冲突多时高效(少重试),但锁等待开销大、死锁风险。
乐观锁(OCC):先干再提交时验证。冲突少时高效(无锁开销),冲突多时大量重试反而慢。

5. 两阶段锁(2PL)——可串行化的经典实现

直觉:事务分两阶段——扩张阶段(只加锁不释放)和收缩阶段(只释放不加锁)。只要严格遵守 2PL,结果必然可串行化。

违反: 提前释放再抢新锁

扩张阶段
按需加锁, 不释放

收缩阶段
释放锁, 不再加锁

可能不可串行化

2PL 的代价

  • 锁等待多,并发度低
  • 死锁:A 等 B 的锁,B 等 A 的锁 → 要检测并杀一个
  • 性能远不如 MVCC

用纯 2PL 的在减少,因为锁开销大、死锁频繁。大多数用 MVCC + 快照隔离,只在需要可串行化时才上 2PL 或 SSI(Serializable Snapshot Isolation,一种结合快照和冲突检测的可串行化方案)。

6. 可串行化的现代实现——SSI

SSI(Serializable Snapshot Isolation):在快照隔离基础上,额外检测"写偏斜"模式的冲突——跟踪事务的读依赖,若多个事务的读依赖可能形成写偏斜,abort 其中一个。比 2PL 性能好(仍是 MVCC 无锁读),但比 SI 有额外跟踪开销。

DDIA 重点是让你知道:可串行化有三条路线:实际串行执行(VoltDB/Redis)、2PL、SSI,其中 SSI 是现代更好的选择,但大多数系统默认不开(快照隔离够用且更快)。


Mermaid:隔离级别与异常对照

隔离级别(从弱到强)

并发异常(从轻到重)

脏读 Dirty Read

不可重复读 Non-repeatable Read

幻读 Phantom

写偏斜 Write Skew

读未提交
⚠️脏读

读已提交
⚠️不可重复读

可重复读
⚠️幻读

快照隔离 SI
⚠️写偏斜

可串行化
✅无异常, 最慢


下一篇:第 8 章——分布式系统的麻烦。分布式系统的部分失效、不可靠网络与时钟。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 10:43:28

DDIA 导读(九):一致性与共识

本文是《Designing Data-Intensive Applications》(DDIA,中文译名《数据密集型应用系统设计》)第 9 章的导读。DDIA 是 Martin Kleppmann 所著的分布式系统经典,本系列逐章导读,把书的核心概念讲清楚。一句话主旨 分布…

作者头像 李华
网站建设 2026/9/13 10:42:30

变压器励磁模型与电压暂降分析的Simulink实现

1. 变压器励磁模型的基础原理与Simulink实现变压器励磁模型是电力系统仿真中的核心组件,它直接影响着电压暂态过程的模拟精度。在Matlab/Simulink环境下,我们通常采用非线性电感模型来表征励磁特性,其本质是描述铁芯磁化曲线的饱和效应。1.1 …

作者头像 李华
网站建设 2026/9/13 10:41:57

Nuclei Templates 完整实战:用 11,000 个模板跑通漏洞扫描

Nuclei Templates 完整实战:用 11,000 个模板跑通漏洞扫描 【免费下载链接】nuclei-templates Community curated list of templates for the nuclei engine to find security vulnerabilities. 项目地址: https://gitcode.com/GitHub_Trending/nu/nuclei-templat…

作者头像 李华
网站建设 2026/9/13 10:41:38

Hermes 编程助手接入 Hindsight:为你的代码库构建跨会话持久记忆

Hermes 编程助手接入 Hindsight:为你的代码库构建跨会话持久记忆 【免费下载链接】hindsight Hindsight: Agent Memory That Learns 项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight 每次 AI 编码会话都从零开始?Hermes 编程…

作者头像 李华