一、MVCC是啥?
MVCC,全称多版本并发控制,是一种维护数据多个版本的机制,使读写操作之间不会发生冲突。MySQL 的快照读通过 MVCC 实现,提供了非阻塞读取功能。MVCC 的实现依赖于数据库记录中的三个隐式字段、Undo log 日志和 ReadView。
二、两种读法:当前读 vs 快照读
当前读
当前读是指读取记录的最新版本。在读取时,为了确保其他并发事务无法修改该记录,系统会对它加锁。常见的当前读操作包括:
- SELECT … LOCK IN SHARE MODE(共享锁)
- SELECT … FOR UPDATE(排他锁)
- UPDATE
- INSERT
- DELETE
快照读
快照读是指简单的 SELECT 操作(不加锁),它读取的是记录数据的可见版本,可能是历史数据,且不会阻塞其他事务。快照读的特点如下:
- Read Committed: 每次 SELECT 都生成一个快照。
- Repeatable Read: 事务开始后的第一个 SELECT 是快照读。
- Serializable: 快照读会退化为当前读。
三、MVCC三大核心法宝
记录中的隐藏字段
- DB_TRX_ID:最近修改该记录的事务 ID。
- DB_ROLL_PTR:回滚指针,指向记录的上一个版本,用于配合 Undo log。
- DB_ROW_ID:隐藏主键,如果表结构没有指定主键,则生成该字段。
时光机:undo log
Undo log 是在 INSERT、UPDATE 和 DELETE 操作时生成的日志,用于数据回滚:
- INSERT: 生成的 Undo log 仅在回滚时需要,事务提交后可以立即删除。
- UPDATE 和 DELETE: 生成的 Undo log 在回滚和快照读时都需要,不会立即删除。
数据版本链
当不同事务或相同事务对同一条记录进行修改时,会形成该记录的 Undo log 版本链。链表头部是最新的旧记录,尾部是最早的旧记录。
四、读视图(ReadView)的筛选规则
ReadView
ReadView 是快照读执行时 MVCC 提取数据的依据,记录当前活跃事务(未提交)的 ID。ReadView 包含四个核心字段:
- **m_ids**: 当前活跃事务 ID 集合
- **min_trx_id**: 最小活跃事务 ID
- **max_trx_id**: 预分配事务 ID(当前最大事务 ID + 1)
- **creator_trx_id**: 创建 ReadView 的事务 ID
版本链数据访问规则
不同的隔离级别生成 ReadView 的时机不同:
- READ COMMITTED: 每次执行快照读时生成 ReadView。
- REPEATABLE READ: 仅在事务中第一次执行快照读时生成 ReadView,后续复用该 ReadView。
RC提取规则
- trx_id 是最近修改事务 ID,对应数据记录中的 DB_TRX_ID。
- 从链表头部开始,依次比较满足提取规则的记录。
RR提取规则
数据可见性判断口诀:
- 如果数据版本的事务ID < min_trx_id → 可见(已提交的老事务)
- 如果事务ID ≥ max_trx_id → 不可见(未来事务修改的)
- 事务ID在[min, max)区间时:
- 若事务ID在m_ids列表 → 不可见(还在活跃未提交)
- 若不在m_ids列表 → 可见(已提交的事务)
五、RC和RR隔离级别的本质区别
隔离级别 | 生成ReadView的时机 | 现象 |
---|---|---|
RC(读提交) | 每次快照读都新生成 | 能看到其他事务的新提交 |
RR(可重复读) | 仅第一次快照读生成,后续复用 | 整个事务看到同一数据版本 |
六、为什么MVCC这么强?
✅ 无锁设计:快照读不阻塞写操作
✅ 版本追溯:通过undo log实现数据时光机
✅ 读写分离:写操作更新最新版,读操作访问历史版