3. 事务隔离级别概述
事务隔离级别是数据库并发控制的核心概念,它决定了事务之间在读取和写入数据时的可见性规则。SQL标准定义了四种隔离级别,从宽松到严格依次为:读未提交、读已提交、可重复读和可序列化。每种级别在解决并发异常(脏读、不可重复读、幻读)的能力上存在差异,同时也对系统吞吐量产生直接影响。
核心认知:隔离级别越高,数据一致性越强,但并发性能越低。支付订单场景需要在一致性与性能之间找到精确平衡点,通常选择读已提交或可重复读作为基线。
3.1 四种并发异常现象
在理解隔离级别之前,必须先掌握三种典型的并发异常现象。这些现象是衡量隔离级别严格程度的标尺。
| 并发异常 | 定义 | 典型场景 | 危害等级 |
|---|---|---|---|
| 脏读 | 事务A读取了事务B尚未提交的数据,若事务B回滚,事务A读到的是无效数据 | 支付订单状态被读取为"已支付",但实际支付事务尚未提交 | 严重 |
| 不可重复读 | 事务A内两次读取同一行数据,结果不一致(因事务B修改并提交了该行) | 订单金额在两次查询之间被其他事务修改 | 中等 |
| 幻读 | 事务A内两次执行同一范围查询,第二次返回了新的行(因事务B插入了新数据) | 统计"待支付订单"数量时,两次结果不一致 | 中等 |
支付安全警示:脏读在支付场景中绝对不可接受。如果订单状态基于未提交的支付结果进行后续发货或退款操作,一旦支付事务回滚,将导致严重的资金损失和业务数据不一致。
3.2 四种隔离级别定义与对比
SQL标准定义的四种隔离级别,通过禁止不同的并发异常来划分严格程度。下表展示了每种级别允许或禁止的异常现象。
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 实现机制(典型) |
|---|---|---|---|---|
| 读未提交 | 可能发生 | 可能发生 | 可能发生 | 不加锁或读操作不加锁 |
| 读已提交 | 禁止 | 可能发生 | 可能发生 | 行级锁 + 快照读(每次查询独立快照) |
| 可重复读 | 禁止 | 禁止 | 可能发生(SQL标准) | 事务开始时刻的快照 + 间隙锁(PostgreSQL实现) |
| 可序列化 | 禁止 | 禁止 | 禁止 | 可序列化快照隔离(SSI)或两阶段锁(2PL) |
PostgreSQL 特别说明:PostgreSQL 的可重复读级别通过快照隔离(Snapshot Isolation)机制,实际上也防止了幻读。这是 PostgreSQL 对 SQL 标准的扩展实现,在支付订单场景中具有重要价值。
3.3 隔离级别与并发异常关系图
下图直观展示了四种隔离级别对三种并发异常的防御能力。箭头方向表示隔离级别逐渐增强,异常防御能力也随之提升。
3.4 各隔离级别行为特征详解
3.4.1 读未提交(Read Uncommitted)
- 行为:事务可以读取其他事务尚未提交的数据修改。
- 风险:脏读是最大隐患,在支付场景中几乎从不使用。
- PostgreSQL 实现:PostgreSQL 实际上将读未提交当作读已提交处理,因为其MVCC架构不允许读取未提交的数据。
3.4.2 读已提交(Read Committed)
- 行为:只能读取到已经提交的数据。每个SQL语句执行时获取独立的快照。
- 优势:避免了脏读,是PostgreSQL的默认隔离级别,也是大多数OLTP系统的首选。
- 支付场景适用性:适合大多数支付订单查询,但需注意不可重复读问题。
3.4.3 可重复读(Repeatable Read)
- 行为:事务开始时刻获取一个快照,整个事务期间所有读操作都基于该快照。
- 优势:避免了脏读和不可重复读,PostgreSQL实现还额外防止了幻读。
- 支付场景适用性:适合需要多次读取同一订单数据且要求一致的场景,如订单对账、退款金额校验。
3.4.4 可序列化(Serializable)
- 行为:事务并发执行的结果必须与某种串行执行顺序一致。
- 优势:最强的隔离保证,完全避免所有并发异常。
- 代价:并发性能显著下降,事务冲突时可能频繁回滚。
- 支付场景适用性:仅用于极高一致性要求的场景,如资金清算、账户余额变更。
3.5 隔离级别选择决策树
在支付订单系统中,选择隔离级别需要根据具体操作类型进行权衡。以下决策树帮助快速定位合适的级别。
3.6 PostgreSQL 隔离级别设置方法
在PostgreSQL中,可以通过会话级别或事务级别设置隔离级别。以下是常用的设置方式。
-- 会话级别设置(影响当前会话所有后续事务)
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 事务级别设置(仅影响当前事务)
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 执行订单查询或更新操作
COMMIT;
-- 查看当前会话的隔离级别
SHOW transaction_isolation;
最佳实践:在支付订单中间件中,建议在连接池层面为不同操作类型预设不同的隔离级别。例如:订单查询连接使用读已提交,订单对账连接使用可重复读,资金结算连接使用可序列化。这样可以最大化系统吞吐量,同时保证关键操作的一致性。
3.7 本章小结
- SQL标准定义了四种隔离级别:读未提交、读已提交、可重复读、可序列化。
- 三种并发异常:脏读、不可重复读、幻读,是衡量隔离级别严格程度的标尺。
- PostgreSQL的读已提交是默认级别,适合大多数支付订单场景。
- PostgreSQL的可重复读通过快照隔离额外防止了幻读,适合对账等需要一致读取的场景。
- 可序列化提供最强一致性保证,但性能代价高,仅用于资金类关键操作。
- 隔离级别的选择需要在一致性与并发性能之间做出权衡,支付系统应根据操作类型差异化选择。