文章目录
- 1. 核心公式:读写不互斥
- 2. 深度拆解:为什么“快照读”敢不加锁?
- 3. 并发量的“质变”
- 4. 总结对比:你的逻辑闭环
- 💡 进阶避坑:一个小细节
没错,你的理解完全正确!
你已经精准地抓住了 MVCC(多版本并发控制)提升并发性能的“任督二脉”。为了让这个逻辑在你的脑海里更稳固,我们可以把这个过程拆解得更深一点,看看数据库引擎在底层是怎么“玩”的。
1. 核心公式:读写不互斥
在没有 MVCC 的传统封锁协议(Locking)中:
- **读锁(S 锁)与写锁(X 锁)**是互斥的。
- **写锁(X 锁)与写锁(X 锁)**更是互斥的。
这意味着只要有人在写,所有人都得等着,并发量被锁死在了单行排队上。
有了 MVCC 后:
- 快照读(Snapshot Read):就是普通的
SELECT。它不申请任何锁,而是通过Read View + Undo Log去读历史快照。 - 当前读(Current Read):包括
UPDATE、DELETE、INSERT以及SELECT ... FOR UPDATE。它们必须获取X 锁来保证数据修改的原子性和一致性。
结论:因为“快照读”不需要锁,它就可以和正在拿着“X 锁”的“当前读”并行发生。
2. 深度拆解:为什么“快照读”敢不加锁?
之所以敢不加锁,是因为 InnoDB 为每一行数据都维护了一个**“平行宇宙”**(版本链)。
- 写操作(当前读):事务 B 正在修改某行。它拿到了 X 锁,把最新数据改了,并把旧数据塞进Undo Log,形成了一个新的版本。
- 读操作(快照读):事务 A 此时过来查询。它不看被锁住的最新版,而是根据自己的Read View顺着Undo Log的指针往回找,找到那个它“有权看到”的历史快照。
3. 并发量的“质变”
这种“读写分离”的架构给系统带来了质的飞跃:
- 消除读写冲突:即使在一个极高频修改的表上(比如秒杀系统的库存表),查询操作依然可以瞬间完成,不会被
UPDATE阻塞。 - 降低锁竞争:在只有“写-写”才需要排队的情况下,系统的吞吐量(TPS/QPS)得到了极大的释放。
- 事务隔离的廉价实现:MVCC 让我们在
Repeatable Read(可重复读)隔离级别下,几乎不用付出额外的锁代价。
4. 总结对比:你的逻辑闭环
| 维度 | 传统加锁模式 | MVCC 模式 |
|---|---|---|
| 读-写交互 | 互斥,必须排队 | 不互斥,并行执行 |
| 性能瓶颈 | 锁的争抢和等待 | 几乎只剩“写-写”锁争抢 |
| 数据一致性 | 靠锁住数据不让别人动 | 靠 Undo Log 溯源历史快照 |
💡 进阶避坑:一个小细节
虽然“读写不互斥”提高了并发,但你要注意:“当前读”和“当前读”之间依然是互斥的。
比如两个事务同时UPDATE同一行,或者一个事务UPDATE时另一个事务SELECT ... FOR UPDATE,它们依然会发生锁等待。
一句话总结你的理解:
因为MVCC 允许读(快照)和写(最新)各走各的路,所以数据库从“单车道”变成了“高架桥”,并发量自然就上去了。