mvcc解决读写互斥问题,innodb通过隐藏字段和undo日志构建版本链,配合readview实现快照读;它支撑rc和rr隔离级别,但当前读仍需加锁。

面试被问到 MVCC,别急着背定义。先说清楚它解决什么问题,再讲 InnoDB 怎么实现,最后点明它和隔离级别的关系——这样三层递进,逻辑清晰,也容易展开细节。
一、MVCC 是为解决“读写互斥”而生的
传统锁机制下,读操作加共享锁、写操作加排他锁,导致读要等写、写也要等读。比如 100 个用户查商品价格(读),商家改价(写)就得排队,高并发直接卡住。
MVCC 的核心价值就是:读不加锁、写不阻塞读。它让读操作看到某个时间点的“快照”,而不是最新数据;写操作则生成新版本,保留旧版本在 undo 日志里。
类比理解:就像多人协作编辑文档,你看到的是打开时的版本,别人另存为新版本,彼此不影响。
二、InnoDB 靠三样东西搭出版本链
每行数据自带两个隐藏字段(有时三个):
BEESSHOW小程序商品展示预约,PHP+MYSQL,Yii2框架。原生微信小程序,电脑端,手机端,管理后台使用VUE element-ui。 一键引导安装,支持虚拟主机、服务器、本地测试。内置演示数据。 主要功能: 商品或服务功能 会员功能 预约订单功能 可以自定义小程序模板,自定义不同的模板页面 适合个人、商家、企业,提供商品展示和服务类微信
- DB_TRX_ID:记录最后一次修改该行的事务 ID,用于判断“谁写的”;
- DB_ROLL_PTR:回滚指针,指向 undo 日志里的上一个版本,串成单向链表;
- DB_ROW_ID(无主键时自动生成):隐式主键,保证行唯一性。
每次 UPDATE 或 DELETE,InnoDB 不覆盖原数据,而是把旧值写进 undo 日志,同时更新 DB_TRX_ID 和 DB_ROLL_PTR,形成一条“版本链”。SELECT 就是顺着这条链,按规则找可见版本。
三、ReadView 决定“你能看到哪个版本”
事务启动时生成 ReadView,包含四个关键信息:
- creator_trx_id:当前事务自己的 ID;
- min_trx_id:当时活跃事务中最小的 ID;
- max_trx_id:系统将要分配给下一个事务的 ID;
- m_ids:生成 ReadView 时所有未提交事务的 ID 列表。
判断某版本是否可见的规则很简单:
- 版本的 DB_TRX_ID 等于 creator_trx_id → 自己写的,可见;
- DB_TRX_ID 小于 min_trx_id → 在你启动前已提交,可见;
- DB_TRX_ID 不在 m_ids 中,且大于等于 min_trx_id → 是已提交事务写的,可见;
- 其余情况 → 不可见,继续沿 DB_ROLL_PTR 往上找。
四、它和隔离级别强绑定,但不是万能的
MVCC 主要支撑 READ COMMITTED 和 REPEATABLE READ 两个级别:
- READ COMMITTED:每次 SELECT 都新建 ReadView,所以能读到其他事务刚提交的新数据(避免脏读,但可能不可重复读);
- REPEATABLE READ:事务第一次 SELECT 时创建 ReadView,后续都复用,保证同一事务内多次读结果一致(避免脏读、不可重复读,但幻读靠间隙锁补足)。
注意:MVCC 只管“快照读”(普通 SELECT),像 SELECT … FOR UPDATE、UPDATE、DELETE 这些“当前读”,仍会加行锁或间隙锁,不能只靠 MVCC。









