事务系统
事务为什么存在?它解决了什么根本问题?人类为此发明了哪些稳定的架构模式?
一、第一性原理层:事务的本质(Why)
1. 事务要解决的根本问题
任何数据库系统都会同时面对三个不可回避的现实约束:
- **并发性(Concurrency)**:多个操作同时发生
- **部分失败(Partial Failure)**:程序、进程、机器随时可能失败
- **状态必须长期正确(State Correctness Over Time)**
事务的本质定义:事务是一种在并发与故障环境下,维持系统状态合法性的控制机制。
它不是 SQL 语法,也不是存储引擎特性,而是一种系统级风险管理机制。
2. 什么是“正确的状态”
“正确”并不是绝对的,而是相对于系统定义的不变量(Invariant):
- 数据不能部分更新
- 并发操作不能相互破坏
- 系统崩溃后状态仍可解释
事务存在的唯一目标是:
确保系统状态的演进,只发生在“允许的状态空间”之内。
3. 一致性的三层语义(必须区分)
| 层次 | 含义 | 责任主体 |
|---|---|---|
| 约束一致性 | 外键、唯一性、Check | 数据库 |
| 事务语义一致性 | 等价于某种串行执行 | 数据库 |
| 业务一致性 | 账户不为负、库存守恒 | 应用 |
ACID 中的 C = 事务语义一致性,而不是业务正确性。
数据库只能保证“你定义的规则被一致地执行”,不能保证规则本身是对的。
二、抽象模型层:事务系统的核心模型(What)
1. 事务是一个状态机
一个事务不是一条语句,而是一个状态演进过程:
- 活动(Active)
- 部分提交(Partially Committed)
- 提交(Committed)
- 失败 / 中止(Failed / Aborted)
所有事务机制,本质上都是在约束状态跳转的合法性。
2. 冲突模型:问题从哪里来
并发问题的根源只有一个:
不同事务对同一状态产生了不可交换的操作顺序。
由此衍生出三类基本冲突:
- 读-写冲突
- 写-读冲突
- 写-写冲突
所有“脏读、不可重复读、幻读”,只是这些冲突在不同可见性规则下的表现形式。
3. 正确性的形式化标准:可串行化
一个并发执行是正确的,当且仅当它等价于某种串行执行。
这是事务系统中最稳定、最根本的正确性标准。
但它的代价是:
- 限制并发
- 增加等待
- 降低吞吐
工程实践的全部努力,都是在**“偏离可串行化多少是可接受的”**这一问题上展开的。
三、机制设计层:人类的三种核心解法(How)
总览:并发控制三大范式
| 范式 | 核心思想 | 关键假设 |
|---|---|---|
| 悲观控制 | 冲突一定会发生 | 先加锁 |
| 乐观控制 | 冲突很少发生 | 先执行后验证 |
| 多版本控制 | 读写不必冲突 | 时间切片 |
1. 悲观控制:锁(Locking)
设计哲学:
与其事后修正错误,不如事前避免错误。
核心特征:
- 读锁 / 写锁
- 两阶段封锁(2PL)
- 严格 2PL → 保证可恢复性
代价:
- 阻塞
- 死锁
- 锁争用
适用场景:
- 写多
- 冲突频繁
- 强一致性优先
2. 乐观控制:验证(Validation)
设计哲学:
假设世界是和平的,冲突是例外。
执行流程:
- 读阶段
- 验证阶段
- 写阶段
优点:
- 高并发
- 无锁读
代价:
- 回滚成本
- 饥饿风险
适用场景:
- 冲突稀少
- 内存系统
- 短事务
3. 多版本控制:MVCC
设计哲学:
与其让事务争抢一个现在,不如让它们各自活在不同的时间片里。
核心思想:
- 写产生新版本
- 读访问旧版本
关键能力:
- 快照
- 可见性规则
- 版本回收
MVCC 本质上是:
用空间换并发,用历史换隔离。
四、事务的四大性质:因果而非并列
1. 原子性(A)
状态跳转要么发生,要么完全不发生。
本质需求:
- 消除中间状态
实现基础:
- Undo Log
2. 隔离性(I)
并发执行对外表现为“好像只有自己在执行”。
本质需求:
- 控制可见性
实现手段:
- 锁
- 版本
- 验证
3. 持久性(D)
已确认的状态,不应因崩溃而消失。
本质需求:
- 状态可重建
实现基础:
- WAL(先日志,后数据)
4. 一致性(C)是结果,而不是手段
C 不是一个独立机制,而是 A + I + D 在正确约束下的自然结果。
五、恢复系统:时间维度上的一致性
1. 为什么必须写日志
磁盘写入不是原子的。
日志是时间顺序的真相来源(Source of Truth)。
2. Undo / Redo 的角色分工
| 日志 | 解决问题 |
|---|---|
| Undo | 回滚未完成事务 |
| Redo | 重放已提交事务 |
3. 恢复算法的统一结构
- 分析(谁活着)
- 重做(恢复已提交)
- 撤销(清理未完成)
ARIES 只是这一结构的经典工程实现。
六、工程实现是选择,而不是本质
不同系统在以下维度做权衡:
- 并发 vs 简单
- 延迟 vs 吞吐
- 一致性 vs 可用性
MySQL、PostgreSQL、Oracle 的差异,
不是原理不同,而是取舍不同。
七、总结:事务系统的稳定认知
- 事务不是 SQL,而是系统控制论
- ACID 是因果关系,不是功能清单
- 可串行化是北极星,而不是日常选择
- MVCC、锁、验证是同一问题的不同答案
- 所有实现细节,都是时代与场景的产物
关联内容(自动生成)
- [/中间件/数据库/数据库优化.html](/中间件/数据库/数据库优化.html) 数据库优化与事务管理密切相关,特别是在并发控制模型、事务隔离级别选择和MVCC成本模型方面
- [/中间件/数据库/分布式数据库.html](/中间件/数据库/分布式数据库.html) 分布式数据库扩展了单机事务的概念,涉及分布式事务、跨节点一致性及多分区共识协议
- [/软件工程/架构/系统设计/分布式/分布式事务.html](/软件工程/架构/系统设计/分布式/分布式事务.html) 分布式事务是单机事务在分布式环境下的延伸,涉及两阶段提交、事务协调等复杂问题
- [/编程语言/JAVA/高级/JDBC.html](/编程语言/JAVA/高级/JDBC.html) JDBC提供了应用程序访问数据库事务管理的接口,实现了ACID特性的编程接口封装
- [/中间件/数据库/mysql/mysql.html](/中间件/数据库/mysql/mysql.html) MySQL作为具体数据库实现,展示了事务管理、锁机制、MVCC等理论的实际应用
- [/中间件/数据库/PostgreSQL.html](/中间件/数据库/PostgreSQL.html) PostgreSQL的MVCC实现提供了另一个事务并发控制的具体实例,有助于理解不同实现方式
- [/编程语言/JAVA/框架/Spring/Spring.html](/编程语言/JAVA/框架/Spring/Spring.html) Spring框架的事务管理抽象了底层数据库事务,提供了声明式事务管理的实现
- [/操作系统/死锁.html](/操作系统/死锁.html) 操作系统中的死锁概念与数据库事务中的锁机制和死锁处理有相似的理论基础和解决策略
- [/中间件/数据库/redis/客户端.html](/中间件/数据库/redis/客户端.html) Redis事务虽然不同于传统ACID事务,但在并发控制和一致性保证方面提供了不同的设计思路
- [/数据技术/数据存储.html](/数据技术/数据存储.html) 数据存储技术中的ACID事务保证是实现数据一致性的基础,与事务管理理论密切相关