MySQL默认隔离级别是REPEATABLE READ,主要依靠MVCC+间隙锁实现:快照读复用事务启动时的Read View,当前读加记录锁与间隙锁防止幻读;RC每次SELECT新建Read View;SERIALIZABLE因强制读加锁致性能骤降。
MySQL默认隔离级别是REPEATABLE READ,但不是靠锁实现的
很多人以为REPEATABLE READ靠的是行锁或表锁来保证多次读一致,其实InnoDB在该级别下主要依赖MVCC(多版本并发控制)+间隙锁(Gap Lock)组合。普通SELECT不加锁,靠的是Read View机制判断哪些版本可见;而UPDATE/DELETE等则会加记录锁+间隙锁防止幻读。
关键点在于:REPEATABLE READ下事务启动时创建Read View,之后所有快照读都复用它;而READ COMMITTED则是每次SELECT都新建Read View。
- RR级别下,事务中第二次
SELECT看到的数据和第一次完全一致,哪怕其他事务已提交修改 - RC级别下,第二次
SELECT可能看到新提交的数据,但不会出现脏读 - RR能避免幻读(通过间隙锁),RC不能——执行
INSERT可能触发唯一键冲突或死锁
MVCC的三个核心组件:DB_TRX_ID、DB_ROLL_PTR、Undo Log
MVCC不是独立模块,而是由每行记录隐含字段和Undo Log协同工作的结果。每条记录包含:
-
DB_TRX_ID:最后修改该行的事务ID -
DB_ROLL_PTR:指向Undo Log中前一版本的指针 - Undo Log里存着历史版本数据和对应
TRX_ID
当执行快照读时,InnoDB根据当前事务的Read View(包含m_ids活跃事务列表、min_trx_id、max_trx_id等)逐条比对记录的DB_TRX_ID,决定是否可见。规则简单说就是:DB_TRX_ID必须小于min_trx_id,或在m_ids中不存在且不大于max_trx_id。
立即学习“Java免费学习笔记(深入)”;
注意:MVCC只对快照读(普通SELECT)生效;当前读(SELECT ... FOR UPDATE、UPDATE、DELETE)会忽略MVCC,直接查最新版本并加锁。