这里写自定义目录标题
-
-
- [**一、MVCC 解决的核心问题**](#一、MVCC 解决的核心问题)
- [**二、MVCC 的核心实现机制**](#二、MVCC 的核心实现机制)
-
- [**1. 隐藏字段与版本链**](#1. 隐藏字段与版本链)
- [**2. Undo Log**](#2. Undo Log)
- [**3. ReadView(一致性视图)**](#3. ReadView(一致性视图))
- [**三、MVCC 的可见性判断过程**](#三、MVCC 的可见性判断过程)
- [**四、不同隔离级别下的 MVCC 行为**](#四、不同隔离级别下的 MVCC 行为)
- [**五、MVCC 的优缺点**](#五、MVCC 的优缺点)
- **六、示例场景**
- **总结**
-
MySQL 的 MVCC(Multi-Version Concurrency Control,多版本并发控制) 是一种用于解决数据库并发读写冲突的机制,旨在提高数据库的并发性能,避免传统锁机制带来的性能开销和阻塞问题。它通过维护数据的多个版本来实现非阻塞的读操作,同时保证事务的隔离性。
一、MVCC 解决的核心问题
- 读写冲突
- 传统锁机制中,读操作可能被写操作阻塞(反之亦然)。MVCC 允许读操作访问历史版本数据,避免读写互相阻塞。
- 事务隔离性
- 在不同事务隔离级别(如
READ COMMITTED
和REPEATABLE READ
)下,MVCC 通过数据快照确保事务看到一致的数据视图。
- 在不同事务隔离级别(如
- 减少锁竞争
- 读操作无需加锁(快照读),减少锁的使用,提高并发性能。
二、MVCC 的核心实现机制
1. 隐藏字段与版本链
InnoDB 每行记录包含以下隐藏字段:
DB_TRX_ID
(6字节):最近修改该行数据的事务 ID。DB_ROLL_PTR
(7字节):指向 undo log 的指针,用于构建数据的历史版本链。DB_ROW_ID
(6字节):隐含的自增行 ID(若未定义主键)。
通过 DB_ROLL_PTR
,InnoDB 将所有旧版本数据以链表形式组织成一条 版本链。
2. Undo Log
- 存储数据的历史版本,用于回滚事务和构建 MVCC 的版本链。
- 每次更新操作会生成 undo log,旧数据通过指针链接到新版本。
3. ReadView(一致性视图)
ReadView 是事务在查询时生成的一致性快照,用于判断数据版本的可见性,包含以下信息:
creator_trx_id
:当前事务的 ID。m_ids
:生成 ReadView 时活跃(未提交)的事务 ID 列表。min_trx_id
:活跃事务中最小的事务 ID。max_trx_id
:生成 ReadView 时系统应分配的下一个事务 ID。
三、MVCC 的可见性判断过程
当事务执行查询时,会遍历数据行的版本链,根据 ReadView 判断每个版本是否可见:
-
判断条件
对版本链中的每个数据版本,按以下规则检查:
- 如果
DB_TRX_ID == creator_trx_id
:该版本由当前事务修改,可见。 - 如果
DB_TRX_ID < min_trx_id
:该版本在 ReadView 生成前已提交,可见。 - 如果
DB_TRX_ID >= max_trx_id
:该版本在 ReadView 生成后修改,不可见。 - 如果
min_trx_id <= DB_TRX_ID < max_trx_id
:- 若
DB_TRX_ID
在m_ids
中,表示该版本由未提交事务修改,不可见。 - 否则,该版本已提交,可见。
- 若
- 如果
-
终止条件
找到第一个可见的版本后停止遍历。若所有版本不可见,则此行数据对当前事务不可见。
四、不同隔离级别下的 MVCC 行为
-
READ COMMITTED(RC)
- 每次查询生成新的 ReadView,能看到其他事务已提交的最新数据。
- 解决脏读,但可能出现不可重复读和幻读。
-
REPEATABLE READ(RR,默认级别)
- 事务首次查询时生成 ReadView,后续沿用同一快照。
- 保证同一事务内多次读取结果一致,解决不可重复读。
- 通过 Next-Key Lock(间隙锁)进一步解决幻读。
五、MVCC 的优缺点
优点:
- 读操作无锁,提升并发性能。
- 避免脏读、不可重复读,部分解决幻读。
缺点:
- 需要维护多版本数据,增加存储和清理成本(通过 Purge 线程清理旧版本)。
- 写操作仍需加锁,可能因版本链过长影响性能。
六、示例场景
假设事务 A(ID=100)在 RR 隔离级别下执行查询:
- 生成 ReadView,此时活跃事务为
[99, 101]
,min_trx_id=99
,max_trx_id=102
。 - 遍历某行数据的版本链,发现其
DB_TRX_ID=98
(小于min_trx_id
),可见。 - 若其他事务修改该行(
DB_TRX_ID=101
),由于 101 在活跃事务列表中,不可见。 - 事务 A 始终使用同一 ReadView,保证可重复读。
总结
MySQL 的 MVCC 通过版本链、ReadView 和 undo log 实现了高效的非阻塞读,解决了读写冲突,同时支持不同隔离级别的事务一致性。其核心在于动态判断数据版本的可见性,平衡了并发性能与数据一致性。