MySQL事务隔离级别实现原理
MySQL 的事务隔离级别主要是通过 多版本并发控制(MVCC) 和 锁机制 协同实现的。不同的隔离级别对应不同的 MVCC 行为规则和锁策略。核心组件是 Undo Log 和 Read View。
1. 读未提交(Read Uncommitted, RU)
实现原理:
无 MVCC 快照: 直接读取数据页上的最新版本,无论该版本是否已提交。
锁机制: 写操作(UPDATE/DELETE)仍需加锁(行锁、间隙锁等),但读操作(SELECT)不加锁(或者加极弱的锁,如
LOCK_IN_SHARE_MODE
但立即释放),所以可能读到脏页。本质: 几乎“禁用”了 MVCC 的快照读功能,直接读物理最新值。
2. 读已提交(Read Committed, RC)
实现原理:
MVCC + 短生命周期 Read View:
每个
SELECT
语句开始执行时,单独生成一个新的 Read View。利用这个新 Read View 和 Undo Log 链,找到该语句启动时已提交的最新版本。
锁机制:
读操作: 默认使用快照读(基于 MVCC),不加锁(除非使用
FOR UPDATE
/LOCK IN SHARE MODE
)。写操作: 需要加锁(行锁、间隙锁)。RC 下仅对扫描到的行加锁,且语句执行完成后可能释放不满足条件的行锁(非事务结束),减少了锁冲突和死锁概率。没有间隙锁,所以可能发生幻读。
关键点: 每次 SELECT 都重新生成 Read View,所以能看到在本次 SELECT 开始前其他事务已提交的修改。
3. 可重复读(Repeatable Read, RR)
实现原理:
MVCC + 长生命周期 Read View:
事务中的第一个
SELECT
语句执行时,生成一个 Read View。后续所有的普通
SELECT
语句都复用这个相同的 Read View。利用这个固定的 Read View 和 Undo Log 链,找到事务第一个 SELECT 启动时已提交的最新版本。因此,在整个事务中看到的都是一致的快照(除非读取自己修改的数据)。
锁机制:
读操作: 默认使用快照读(基于 MVCC),不加锁。
写操作: 需要加锁。为了解决幻读问题,RR 引入了 Next-Key Locking(临键锁 = 行锁 + 间隙锁)。它锁定的不仅是扫描到的行,还包括行之间的间隙,防止其他事务在范围内插入新行(导致幻读)。
关键点:
快照读的“可重复读”: 由复用同一个 Read View 保证。
防止幻读: 主要由 Next-Key Locking 在当前读(
SELECT ... FOR UPDATE
/UPDATE
/DELETE
)时保证。纯快照读理论上仍可能看到幻象(如果依赖快照读做业务决策可能有问题),但 InnoDB 的 RR 通过 Next-Key Lock 基本避免了幻读。当前读: 当执行
UPDATE
、DELETE
或SELECT ... FOR UPDATE
时,即使有快照,也必须读取最新已提交的数据并加锁(Next-Key Lock),以确保数据一致性和防止并发修改冲突。
4. 可串行化(Serializable)
实现原理:
基本“禁用”快照读: 所有普通的
SELECT
语句会被自动隐式转换为SELECT ... LOCK IN SHARE MODE
。锁机制:
读操作: 加共享锁(S 锁)。
写操作: 加排他锁(X 锁)。
效果: 读写、写写操作都会相互阻塞。通过严格的两阶段锁(2PL) 和 Next-Key Locking 实现最高隔离,性能最低。
本质: 退化为基于锁的并发控制,MVCC 的快照读在此级别基本失效。