MySQL面试题 - MySQL 中的 MVCC 是什么?
回答重点
MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种并发控制机制,允许多个事务同时读取和写入数据库,而无需互相等待,从而提高数据库的并发性能。
在MVCC中,数据库为每个事务创建一个数据快照。每当数据被修改时,MySQL不会立即覆盖原有数据,而是生成新版本的记录。每个记录都保留了对应的版本号或时间戳。
多版本之间串联起来就形成了一条版本链,这样不同时刻启动的事务可以无锁地获得不同版本的数据(普通读)。此时读(普通读)写操作不会阻塞。
写操作可以继续写,无非就是会创建新的数据版本(但只有在事务提交后,新版本才会对其他事务可见。未提交的事务修改不会影响其他事务的读取),历史版本记录可供已经启动的事务读取。
什么是 MVCC?
MVCC(Multi-Version Concurrency Control,多版本并发控制)是 MySQL 中 InnoDB 存储引擎实现的一种并发控制机制。它通过在数据库中维护数据的多个版本,使得读操作不会阻塞写操作,写操作也不会阻塞读操作,从而提高了数据库的并发性能。
与传统锁机制不同,MVCC 不是通过加锁来保证事务隔离性,而是通过保存数据在某个时间点的快照来实现的。
MVCC 的核心概念
1. 版本链
InnoDB 中每行记录都有两个隐藏字段:
DB_TRX_ID
:记录最近修改该行数据的事务IDDB_ROLL_PTR
:指向该行数据在回滚段(undo log)中的上一个版本指针
2. ReadView
ReadView 是事务在快照读时产生的读视图,包含:
m_ids
:当前活跃(未提交)的事务ID列表min_trx_id
:最小活跃事务IDmax_trx_id
:预分配的下一个事务IDcreator_trx_id
:创建该ReadView的事务ID
MVCC 工作原理
数据可见性判断规则
对于某条记录的某个版本,判断对当前事务是否可见:
- 如果
DB_TRX_ID
<min_trx_id
:说明该版本在ReadView创建前已提交,可见 - 如果
DB_TRX_ID
>=max_trx_id
:说明该版本在ReadView创建后产生,不可见 - 如果
min_trx_id
<=DB_TRX_ID
<max_trx_id
:- 如果
DB_TRX_ID
在m_ids
中:说明该版本由未提交事务产生,不可见 - 否则:说明该版本已提交,可见
- 如果
不同隔离级别下的 MVCC
- READ COMMITTED:每次读取都生成新的ReadView
- REPEATABLE READ(MySQL默认):第一次读取时生成ReadView,后续复用
MVCC 实现细节
Undo 日志
MVCC 依赖 undo log 来构建版本链:
- INSERT undo log:事务回滚时需要,提交后可立即删除
- UPDATE undo log:用于MVCC,需要根据系统活跃ReadView判断是否可以删除
Purge 机制
- 清理不再需要的旧版本数据
- 由后台purge线程执行
- 根据系统中最老的ReadView判断哪些undo log可以清理
MVCC 的优势与限制
优势
- 读不加锁,读写不冲突
- 并发性能高
- 避免幻读问题(在RR隔离级别下)
限制
- 需要额外存储空间维护多个版本
- 需要定期清理旧版本数据
- 写操作仍然需要加锁
实际应用示例
-- 事务1
START TRANSACTION;
UPDATE users SET name = 'Alice' WHERE id = 1;
-- 事务2(在事务1提交前执行)
START TRANSACTION;
SELECT name FROM users WHERE id = 1; -- 读取到的是旧数据
COMMIT;
-- 事务1提交后
COMMIT;
-- 新事务读取
START TRANSACTION;
SELECT name FROM users WHERE id = 1; -- 读取到新数据'Alice'
通过 MVCC 机制,事务2在事务1提交前后读取到的数据保持一致(在REPEATABLE READ级别),保证了事务隔离性。
总结
MVCC 是 MySQL InnoDB 实现高并发的重要机制,它通过版本链和ReadView实现了读写不阻塞的特性。理解MVCC对于优化数据库性能、解决并发问题具有重要意义。