太专业了!你提到的这个“读取快照”的技术,正式名称叫 MVCC(Multi-Version Concurrency Control,多版本并发控制)。
它是 MySQL 实现高并发的核心黑科技。简单来说:锁是用来封锁变动的,而 MVCC 是用来实现“不加锁也能读”的。
它们的逻辑关系如下:
1. 为什么要有“快照读”?
在早期的数据库里,读会锁住写,写会锁住读。
-
痛点:如果你在备份一个 10GB 的表(读),那这期间谁也别想往里存数据(写),业务直接瘫痪。
-
解决方案:MVCC。它让数据库可以同时看到数据的多个版本。你改你的,我读我那一刻的“快照”,互不干扰。
2. 快照读 vs. 当前读 (这是核心差异)
这是区分资深开发与初级开发的分水岭:
-
快照读 (Snapshot Read):
-
语法:普通的
SELECT * FROM table ...。 -
原理:不加锁,读取的是 ReadView(一致性视图)。它像一张照片,记录了事务启动那一刻数据长什么样。
-
-
当前读 (Current Read):
-
语法:
SELECT ... FOR UPDATE或UPDATE / INSERT / DELETE。 -
原理:必须加锁(也就是我们刚才聊的 Record/Gap/Next-Key Lock)。因为它要修改数据,必须拿到“最新版本”的那一行。
-
3. 快照在不同隔离级别下的表现
你记记得“读提交”有快照,没错,但它和“可重复读”生成的快照时机不同:
RC(读提交):每次查询都拍新照片
-
在一个事务里,你执行两次
SELECT。 -
第一次
SELECT拍一张快照。 -
如果中间别人提交了新数据,你第二次
SELECT会重新拍一张快照。 -
结果:两次看到的不一样(不可重复读)。
RR(可重复读):整个事务只拍一张照片
-
事务开始后的第一次
SELECT拍下一张快照。 -
无论后面别人怎么改、怎么提交,你后续所有的
SELECT都只看第一张照片。 -
结果:这就是为什么叫“可重复读”。
4. MVCC 是怎么实现“照片”的? (Undo Log)
MySQL 并没有真的把整张表复制一份。它是靠每行数据后面的两个隐式字段:事务 ID(DB_TRX_ID) 和 回滚指针(DB_ROLL_PTR)。
当数据被修改时,旧版本会被存在 Undo Log(回滚日志) 里,形成一个版本链。快照读其实就是顺着这条链,找那个它“有权看到”的最新的旧版本。
🛠 总结:锁与快照的关系
-
快照(MVCC):解决了 读-写 冲突。让读不需要等写,性能起飞。
-
锁(Record/Gap/Next-Key):解决了 写-写 冲突。确保两个人都改同一行时,不会把数据改乱。
所以,当你用普通的 SELECT 时,你在用“快照”;当你用 UPDATE 或 FOR UPDATE 时,你在用“锁”。
既然你连 MVCC 都想起来了,需要我带你看看 Undo Log 的版本链长什么样吗?或者聊聊为什么有些长事务会导致 Undo Log 撑爆硬盘?