现代应用不在真空中运行。每次预订乘车、购买商品或更新余额时,后端都要处理多个操作(读取、写入、验证),通常跨不同表或服务。这些操作必须要么一起成功,要么作为整体失败。

这就是事务介入的地方。

数据库事务将一系列操作包装成全部或全无的单元。要么整个提交并对世界可见,要么都不。换句话说,目标是没有半途而废的订单、没有不一致的账户余额、没有幽灵预订。

然而,当并发进入画面时,维护正确性变得更难。

这是因为事务不在隔离中运行。真实系统处理数十、数百或数千同时用户。每个用户都期望他们的操作成功。在幕后,数据库必须平衡隔离、性能和一致性,而不使系统停滞。

这个平衡行为不平凡。以下是一些情况:

  • 一个事务可能读取另一个即将更新的数据
  • 两个用户可能尝试预订相同库存槽
  • 后台作业可能在客户点击”确认”前锁定记录

这些场景可能导致冲突、竞态条件和死锁,完全停滞系统。

在本文中,我们分解使事务系统在面对并发时可靠的关键构建块。我们将从基础开始:什么是事务,以及为什么 ACID 属性重要。然后我们将深入并发控制机制(悲观和乐观)并理解相关权衡。

ACID 属性

原子性(Atomicity)

事务中的所有操作要么全部成功,要么全部失败。没有中间状态。

一致性(Consistency)

事务执行后,数据库必须保持在一致状态。所有约束、触发器和规则必须满足。

隔离性(Isolation)

并发执行的事务必须相互隔离。一个事务的中间状态对其他事务不可见。

持久性(Durability)

一旦事务提交,更改永久保存,即使系统故障。

并发控制

悲观并发控制

假设冲突会发生,提前获取锁防止冲突。

优点

  • 防止冲突
  • 适合高冲突场景

缺点

  • 可能导致死锁
  • 降低并发性能

乐观并发控制

假设冲突很少发生,在提交时检查冲突。

优点

  • 高并发性能
  • 无死锁风险

缺点

  • 冲突时需要重试
  • 不适合高冲突场景

本文为学习目的的个人翻译,译文仅供参考。

原文链接:A Guide to Database Transactions: From ACID to Concurrency Control

版权归原作者或原刊登方所有。本文为非官方译本;如有不妥,请联系删除。