隔离级别与并发异常复现(实验)

kp-015 · 事务与并发控制核心约 30 分钟已校对

前置知识点

前置:

相关知识点

相关:

学习进度:

一句话定义

隔离级别(Isolation Level)是隔离强度的四级标尺——读未提交、读已提交、可重复读、串行化——每一级对应「允许/禁止哪些并发异常」(脏读、不可重复读、幻读、丢失更新)。

为什么重要

前置知识

kp-014(事务生命周期、COMMIT/ROLLBACK)。

核心概念

原理与机制

SQL 标准用「允许的异常集」定义级别,Berenson 等人 1995 年指出标准定义的漏洞(幻读定义过窄),各实现自行取舍:PostgreSQL 的 RC 每条语句取新快照(语句级一致),RR 取事务首快照并用 SIRead 锁检测串行化异常;MySQL InnoDB 的 RC 每语句快照,RR 事务首快照且靠间隙锁(kp-016)阻止他人在扫描区间插入,从而抑制幻读。丢失更新不被标准四级显式覆盖,是 RR 下仍会发生的经典坑:两个事务都 SELECT balance 后各自 UPDATE,后写覆盖先写——解法是显式 SELECT ... FOR UPDATE 行锁、原子 UPDATE ... SET x = x - ? WHERE ...、或乐观版本号 WHERE version = ?。设置方式:MySQL SET SESSION TRANSACTION ISOLATION LEVEL ...,PG SET default_transaction_isolation = ...。

实例或案例

可复现实验:两会话 A/B,表 account(user_id INT PRIMARY KEY, balance INT),初始 (1, 1000),以下按行号交替执行(MySQL 默认 RR;PG 建议先测 RC 再切 RR 对比)。

-- 两会话 A/B,表: account(user_id INT PRIMARY KEY, balance INT)
-- 初始: (1, 1000)。以下按行号交替执行,MySQL 默认 RR / PG 建议先测 RC 再切 RR 对比

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- A1: BEGIN;
-- B1: BEGIN;
-- A2: UPDATE account SET balance = balance - 100 WHERE user_id = 1;
-- B2: SELECT balance FROM account WHERE user_id = 1;   -- RC 下看到 1000(A 未提交,无脏读)
--                                                        (切到 READ UNCOMMITTED 会看到 900:复现脏读)
-- A3: COMMIT;
-- B2'(重复读): SELECT balance FROM account WHERE user_id = 1;  -- RC 下变成 900:复现不可重复读
--                                                              (RR 下仍是 1000:快照可重复读)
-- B3: SELECT COUNT(*) FROM account WHERE balance > 500;  -- 另一会话插入新行后再执行一次,
--                                                        -- RC 下计数变化:复现幻读;RR/快照下不变

丢失更新实验:A、B 都在 RC 下 SELECT balance 得 1000,各自 UPDATE ... SET balance = 1000 - 100 与 - 200,最终余额 800 或 900 而非 700——后写覆盖先写。

常见误区

自测题

  1. RC 与 RR 的快照粒度差异是什么? 答:RC 每条语句开始时取新快照(能看到他事务新提交),RR 取事务第一条查询时的快照并贯穿全程。
  2. 为什么 RR 仍可能丢失更新?如何根治? 答:两个事务基于同一快照值各自覆盖写;根治手段是悲观行锁(SELECT FOR UPDATE)、原子自增式 UPDATE 或乐观并发(版本号条件更新+重试)。

公式或模型

本节不适用:隔离级别是异常集合的分级定义(四级别 × 四异常的矩阵),不是定量公式。

图示

本节不适用:本库以可执行实验代替时间线图——亲手跑一遍 A/B 会话交替脚本,异常出现的那一刻即是最好的图。

直观类比

隔离级别像会议室的隔音等级:读未提交是薄纱隔断(对方草稿都能看见);读已提交是普通墙(定稿才听见,但你说话时别人可以改文件);可重复读是套房(你开会期间房间内一切不变);串行化是排队使用同一间房。

与其他知识点的关系

kp-016 与 kp-017 是实现隔离的悲观/乐观两大路线;kp-018 讨论跨节点时隔离性的代价;kp-029 中「并发下丢库存」是最常见的业务化表达。

延伸阅读