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参数,判断优先级从高到低:
-
trx_id == creator_trx_id:自己改的数据,可见;
-
trx_id < min_trx_id:生成该版本的事务已提交,可见;
-
trx_id >= max_trx_id:生成该版本的事务后于当前事务开启,不可见;
-
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隔离级别的数据一致性。