一、什么是MVCC?
想象一下图书馆借书的场景:当一本书被借走时,其他人仍然可以查看这本书的信息,只是不能借出。数据库中的 MVCC(Multi-Version Concurrency Control,多版本并发控制)机制也是类似的思路——它让读写操作可以同时进行,而不会互相阻塞。
MVCC 是 InnoDB 存储引擎实现高并发的重要机制。它的核心思想是:每个事务看到的数据版本可能不同,而不是直接锁定数据。这样,读操作不会阻塞写操作,写操作也不会阻塞读操作,从而提升数据库的并发性能。
二、MVCC 的核心实现原理
MVCC 的实现依赖于三个关键机制:
隐藏字段
InnoDB 在每行记录中隐藏存储了三个字段:DB_TRX_ID:记录最后一次修改该行的事务 ID。DB_ROLL_PTR:指向该行的 undo log(回滚日志)指针,用于找到旧版本数据。DB_ROW_ID:行 ID(如果没有主键,InnoDB 会自动生成)。
ReadView(读视图)
事务在读取数据时,会生成一个 ReadView,包含:m_ids:当前活跃(未提交)的事务 ID 列表。min_trx_id:当前活跃事务中的最小事务 ID。max_trx_id:下一个即将分配的事务 ID。creator_trx_id:创建该 ReadView 的事务 ID。
Undo Log(回滚日志)
当事务修改数据时,InnoDB 会先将旧数据写入 undo log,再修改内存中的数据。如果事务回滚,可以通过 undo log 恢复数据。
三、MVCC 如何判断数据可见性
当一个事务执行查询时,InnoDB 会按照以下规则判断某行数据是否可见:
- 如果该行的
DB_TRX_ID小于min_trx_id,说明该行在事务开始前就已提交,可见。 - 如果
DB_TRX_ID大于等于max_trx_id,说明该行是未来事务修改的,不可见。 - 如果
DB_TRX_ID在m_ids中,说明该行由未提交事务修改,不可见。 - 如果
DB_TRX_ID等于creator_trx_id,说明该行由当前事务修改,可见。
示例(MySQL 8.0+):
-- 事务1:修改数据
START TRANSACTION;
UPDATE users SET name = 'Alice' WHERE id = 1;
-- 此时事务未提交,其他事务看不到这个修改
-- 事务2:查询数据
START TRANSACTION;
SELECT name FROM users WHERE id = 1; -- 看到的是旧数据
COMMIT;
-- 事务1提交后,其他事务才能看到新数据
COMMIT;
四、MVCC 的应用场景
读多写少的业务
例如电商的商品浏览、新闻网站的阅读,MVCC 可以让大量读操作不阻塞写操作。长事务与短事务共存
报表查询(长事务)不会阻塞订单处理(短事务)。避免幻读(在 REPEATABLE READ 隔离级别下)
InnoDB 通过 MVCC + 间隙锁(Gap Lock)防止幻读。
五、MVCC 的优缺点
优点:
- 读写不冲突,提高并发性能。
- 避免脏读、不可重复读(取决于隔离级别)。
缺点:
- 需要额外存储 undo log,占用空间。
- 长时间运行的事务可能导致 undo log 堆积,影响性能。
六、注意事项
避免长事务
长时间不提交的事务会阻止 undo log 清理,可能导致数据库膨胀。合理设置隔离级别
READ COMMITTED:每次查询生成新 ReadView,可能不可重复读。REPEATABLE READ(默认):事务内使用同一个 ReadView,保证可重复读。
监控 undo log 使用情况
SHOW ENGINE INNODB STATUS\G -- 查看 undo log 信息
七、总结
MVCC 是 InnoDB 实现高并发的核心机制,通过数据多版本和 ReadView 实现读写并行。理解它的原理,可以帮助我们更好地设计数据库事务,避免性能问题。
评论