Innodb Mvcc

MVCC是InnoDB实现高效并发的核心技术,核心是“多版本无锁读”

一、为什么需要MVCC?(核心痛点)

传统锁机制(行锁、表锁)会导致“读写互斥”,高并发下吞吐量暴跌;MVCC解决此问题,实现读写不阻塞、写写才阻塞,同时避免脏读、不可重复读、幻读,兼顾一致性和性能。

适用隔离级别:读已提交(RC)、可重复读(RR)(MySQL默认RR)。

二、MVCC核心定义与思想

2.1 核心定义

MVCC(多版本并发控制):为每一行数据维护多个历史版本,每个版本关联事务ID,事务读取时,根据规则选择可见版本,实现“无锁读”。

2.2 核心思想

本质是“快照读”:事务读的是数据的“快照版本”(不是最新版),写操作生成新版本,不影响旧版本读取,因此读写互不干扰(类比:看书不影响别人写书)。

三、MVCC底层三大核心组件

3.1 隐藏字段(每行数据自带)

  • DB_TRX_ID(4字节):生成当前数据版本的事务ID(自增,越大越新);

  • DB_ROLL_PTR(8字节):回滚指针,指向undo log中的上一版本,串联成“版本链”;

  • DB_ROW_ID(6字节):无显式主键时自动生成,唯一标识行数据(有主键可忽略)。

3.2 Undo Log(回滚日志)

核心作用:① 事务回滚(恢复数据);② 维护版本链(修改数据时,旧版本写入undo log,通过回滚指针关联)。

版本链简化示例:当前版本(王五,TRX_ID=102)→ 回滚指针 → undo log(李四,TRX_ID=101)→ 回滚指针 → undo log(张三,TRX_ID=100)。

补充:undo log会自动清理,无事务访问时删除,避免占用内存。

3.3 ReadView(读视图)

事务快照读时生成的临时视图,用于判断数据版本是否可见,包含4个核心参数:

  • m_ids:当前活跃(未提交)的事务ID集合;

  • min_trx_id:m_ids中最小的事务ID;

  • max_trx_id:系统下一个要分配的事务ID(已分配最大ID+1);

  • creator_trx_id:当前事务自身的ID。

四、MVCC核心:可见性判断规则

假设数据版本的DB_TRX_ID = trx_id,结合ReadView参数,判断优先级从高到低:

  1. trx_id == creator_trx_id:自己改的数据,可见;

  2. trx_id < min_trx_id:生成该版本的事务已提交,可见;

  3. trx_id >= max_trx_id:生成该版本的事务后于当前事务开启,不可见;

  4. min_trx_id < trx_id < max_trx_id:在m_ids中(事务活跃)→ 不可见;不在m_ids中(事务已提交)→ 可见。

补充:不可见则顺着版本链往下找,直到找到可见版本或结束。

五、RC和RR隔离级别下的MVCC差异

核心差异:ReadView生成时机不同,直接影响读取结果:

  • RR(可重复读):事务中第一次select时生成一次ReadView,全程复用 → 整个事务看到的数据一致,避免不可重复读;

  • RC(读已提交):每次select都重新生成ReadView → 每次都能读到其他事务刚提交的最新数据,可能出现不可重复读。

六、补充

  • MVCC只适用于“快照读”(普通select,不加锁);

  • “当前读”(select … for update、update、delete、insert)加锁,不走MVCC,读最新版本;

  • RR级别解决幻读:MVCC(快照读避免看到新插入数据)+ 间隙锁(当前读锁住范围,禁止插入);

  • 一句话总结:MVCC靠“隐藏字段+undo log版本链+ReadView判断”,实现读写不阻塞,支撑RC和RR隔离级别的数据一致性。