# 事务与并发控制

> CIE A-Level 计算机科学 · 9618
> 来源: https://www.owlsprep.com/zh/study/cie-9618-u8-transactions-and-concurrency-control/

本模块介绍数据库事务的定义和属性、并发访问导致的常见不一致问题，以及多用户数据库系统中控制并发、维护数据完整性的标准方法。

**先修:** [关系数据库概念](https://www.owlsprep.com/zh/study/cie-9618-u8-relational-database-concepts/); [SQL数据操作](https://www.owlsprep.com/zh/study/cie-9618-u8-sql-data-manipulation/)

## 学习目标

- 解释数据库事务的四个核心ACID属性
- 识别并分类多用户数据库中常见的并发异常
- 描述并比较不同的并发控制方法
- 运用概念解决事务完整性相关的考试风格问题

## 事务与ACID属性

事务是数据库中的逻辑工作单元，由一个或多个数据库操作（例如读、写、更新或删除）组成。事务被设计为单个不可分割的单元，即使发生错误或多个并发访问，也能维护数据完整性。

**事务** — 构成单个逻辑工作单元的一系列数据库操作，如果任何部分失败，必须全部完成（提交）或完全不完成（回滚）。

*例:* 从储蓄账户向支票账户转账\$100，需要两次更新：从储蓄账户减去100，向支票账户加上100。

- 所有可靠的数据库系统都要求事务遵循四个核心属性，即**ACID属性**：
- * **原子性**：事务中的所有操作要么全部成功完成，要么全部不执行；如果任何步骤失败，数据库将回滚到事务开始前的状态。
- * **一致性**：事务必须将数据库从一个有效状态转换到另一个有效状态，始终遵守所有预定义的数据库规则（约束、完整性规则）。
- * **隔离性**：并发运行的事务不会互相干扰；每个事务的表现就像它独自在数据库上运行一样。
- * **持久性**：一旦事务提交，其修改就是永久的，能够经受任何系统崩溃或断电。

**例题:** 从账户A向账户B转账\$500的银行事务，在系统借记账户A之后、贷记账户B之前中途失败。哪个ACID属性保证数据库恢复到原始状态？

1. 1. 明确需求：我们需要撤销部分事务，不给数据库留下任何部分修改。
2. 2. 回顾：原子性保证事务的所有操作要么全部完成，要么全部不完成，不允许存在部分修改。
3. 3. 数据库会回滚对账户A的借记操作，将两个账户恢复到事务开始前的原始余额。

> **考试提示:** CIE考试经常要求你命名并解释每个ACID属性，你必须能定义全部四个属性，而不只是命名，考试要求你描述每个属性的含义。

## 常见并发异常

当多个事务同时（并发）访问同一数据库数据时，即使每个事务单独运行都是正确的，它们也会互相干扰，产生不一致的结果。这些不一致被称为并发异常。

**并发异常** — 多个事务访问同一数据的无控制并发执行导致的数据库状态不一致。

- CIE考试经常考察三种主要的并发异常：
- 1. **脏读**：一个事务读取了未提交事务写入的数据，如果未提交事务被回滚，读取到的数据就是无效的。
- 2. **不可重复读**：一个事务两次读取同一行，得到不同的值，因为另一个事务在两次读取之间修改并提交了该行。
- 3. **幻读**：一个事务两次运行同一个查询，得到不同的行数，因为另一个事务在两次查询之间插入或删除了行并提交。

**例题:** 事务1为所有超过\$1000的订单添加10%折扣，尚未提交。事务2读取所有订单，包括事务1更新后的折扣，生成销售报告。随后事务1被回滚。这属于哪种异常？

1. 1. 注意：事务2读取了未提交事务（事务1）修改的数据，该数据随后被回滚，因此报告包含无效数据。
2. 2. 将该描述与脏读的定义匹配，脏读的定义就是读取另一个事务未提交的修改。
3. 3. 确认这不是不可重复读，不可重复读要求读取事务两次读取同一数据，本场景中没有发生这种情况。

## 并发控制：锁机制

锁机制是应用最广泛的并发控制方法。其工作原理是让事务在访问数据项之前获取锁，防止其他事务的冲突访问。

**锁机制** — 一种并发控制方法，将数据项的访问限制为仅允许兼容的事务，防止对共享数据的冲突修改。

- 大多数锁机制系统使用两种常见的锁类型：
- * **共享（读）锁**：多个事务可以对同一数据项持有共享锁。当事务仅需要读取数据、不修改时，获取共享锁。
- * **排他（写）锁**：任意时刻只能有一个事务对数据项持有排他锁。当事务需要修改数据时，获取排他锁。

**例题:** 事务A想要读取账户X的余额，然后更新它。它应该获取什么锁，为什么？

1. 1. 事务A需要防止另一个事务在它完成读取和更新序列的过程中修改账户X的余额。
2. 2. 由于事务A最终要修改余额，它需要从一开始就获取账户X的排他锁（或者之后将共享锁升级为排他锁）。
3. 3. 排他锁会阻止任何其他事务读取或写入账户X，直到事务A提交或回滚，因此不会发生冲突修改。

> **tip**
>
> 当两个或多个事务各自持有对方需要的锁，都无法继续执行时，就会发生死锁。大多数数据库系统会自动检测死锁，回滚其中一个事务来打破死锁。

## 其他并发控制方法

除了锁机制之外，还有其他并发控制方法可以避免锁机制的一些缺点，例如死锁。CIE考试考察的两种常见方法是时间戳排序和乐观并发控制。

- * **时间戳排序**：每个事务在启动时被分配一个唯一时间戳。只有当事务的时间戳早于该数据项上任何读/写操作的最新时间戳时，事务才能写入该数据项。冲突事务会被回滚，并用新时间戳重启。
- * **乐观并发控制**：该方法假设事务之间的冲突很少发生，因此它允许事务不获取锁就执行，仅在事务尝试提交时检查冲突。如果发现冲突，事务会被回滚并重启。

**例题:** 一个低流量博客数据库，多个作者同时编辑文章，冲突修改非常少。锁机制和乐观并发控制哪个是更好的选择？

1. 1. 该用例流量低，事务之间冲突极少，符合乐观并发控制的设计目标。
2. 2. 对于冲突很少的系统，锁机制会增加不必要的开销，降低并发度，因为每次访问都需要获取锁。
3. 3. 当冲突很少时，乐观并发控制性能更高，因为它避免了事务执行过程中的锁开销。

**方法对比**

下表总结比较了三种主要的并发控制方法：

- **锁机制** — 访问前锁定数据，防止冲突
  - 优点: 适用于高竞争（冲突多）的系统
  - 缺点: 可能导致死锁，降低整体并发度

- **时间戳排序** — 使用时间戳对事务排序，回滚冲突事务
  - 优点: 不会发生死锁
  - 缺点: 高竞争系统的回滚率高

- **乐观并发控制** — 仅在提交时检查冲突
  - 优点: 并发度高，无死锁，冲突稀少时开销低
  - 缺点: 冲突频繁时性能差，回滚次数多

## 常见错误

- **错误做法:** 描述ACID属性时混淆原子性和一致性
  - 原因: 原子性涉及撤销部分事务，而一致性涉及事务遵守所有数据库规则
  - 正确做法: 记住：原子性 = 事务步骤要么全有要么全无；一致性 = 最终数据库状态始终有效
- **错误做法:** 将任何涉及数据更改的并发问题都称为不可重复读
  - 原因: 脏读的核心特征是读取了后续被回滚的未提交数据。不可重复读涉及两次读取已提交的修改后数据
  - 正确做法: 检查问题是否涉及读取未提交修改：如果是，就是脏读，不是不可重复读
- **错误做法:** 声称多个事务可以对同一数据项持有排他锁
  - 原因: 写操作需要排他锁，每个数据项只能持有一个排他锁，以防止冲突写入
  - 正确做法: 共享锁 = 允许多个读取；排他锁 = 仅允许单个事务访问进行写入
- **错误做法:** 认为乐观并发控制使用锁来防止冲突
  - 原因: 乐观并发控制假设冲突很少，因此执行过程中不使用锁
  - 正确做法: 只有基于锁的方法在执行过程中使用锁；乐观并发控制在提交前是无锁的
- **错误做法:** 声称持久性保证未提交修改能在系统崩溃后保留
  - 原因: 持久性仅适用于成功提交事务的修改
  - 正确做法: 只有已提交修改保证是持久的，能经受系统崩溃；未提交事务在崩溃后会被回滚

## 速查表

| 概念 | 核心要点 |
| --- | --- |
| 原子性 | 所有事务步骤要么全部完成，要么全部不执行 |
| 一致性 | 事务使数据库保持有效状态 |
| 隔离性 | 并发事务互不干扰 |
| 持久性 | 已提交修改是永久的 |
| 脏读 | 读取未提交、已回滚的数据 |
| 不可重复读 | 同一行读取两次得到不同值 |
| 幻读 | 同一查询返回不同行数 |
| 共享锁 | 多个事务可以读取同一数据 |
| 排他锁 | 只有一个事务可以修改数据 |
| 乐观并发控制 | 提交时检查冲突，冲突稀少时无需锁 |

## 下一步

理解事务与并发控制对于设计可靠的多用户数据库系统至关重要，这是CIE A-Level计算机科学试卷2中经常考察的考点。本子主题建立在关系数据库核心概念的基础上，是数据库恢复、分布式数据库等更高级主题的基础。掌握ACID属性和并发异常有助于你回答考试中数据库设计相关的简答题和论述题。

- [算法设计与问题求解](https://www.owlsprep.com/zh/study/cie-9618-u9-overview/)
- [计算思维基础](https://www.owlsprep.com/zh/study/cie-9618-u9-computational-thinking-fundamentals/)
- [问题解决流程](https://www.owlsprep.com/zh/study/cie-9618-u9-problem-solving-process/)

---

来自 [OwlsPrep](https://www.owlsprep.com) —— A-Level / IB / AP / IGCSE 免费学习指南，依据官方考纲编写。原页面：https://www.owlsprep.com/zh/study/cie-9618-u8-transactions-and-concurrency-control/
