在 MySQL 的 InnoDB 存储引擎中,存在两种不同的读取模式:当前读(Current Read) 和 快照读(Snapshot Read)。这两者在事务并发控制中扮演着不同的角色,并通过不同的机制来确保数据一致性。下面解释它们的区别及应用场景。
一、当前读
(Current Read)
定义:当前读指的是读取数据的最新版本,无论其他事务是否对这些数据做了修改,只要事务已经提交,当前读都能看到这些修改。当前读通常会加锁,确保在读取和修改期间数据的一致性。
适用场景:
当前读通常用于需要修改数据的操作(INSERT、UPDATE、DELETE),因为这些操作需要确保读取的最新数据是其他事务不可修改的。以下操作都是当前读:
SELECT ... FOR UPDATE (加排它锁)
SELECT ... LOCK IN SHARE MODE (加共享锁)
UPDATE
DELETE
INSERT
工作原理:
在执行当前读操作时,事务会对所读取的行加锁,防止其他事务修改这些行。例如,在执行 SELECT ... FOR UPDATE 时,事务会对查询结果中的每一行加上排它锁,其他事务在该行上的更新或删除操作将被阻塞,直到当前事务提交或回滚。
例子:假设有两个事务 A 和 B:
事务 A 执行 SELECT ... FOR UPDATE 读取了一些行,并对这些行加锁。
事务 B 想要更新或插入这些行,会被阻塞,直到事务 A 完成。
事务 A 能看到其他事务已经提交的修改。
二、快照读
(Snapshot Read)
定义:快照读是通过多版本并发控制(MVCC)来实现的,它读取的是事务启动时的历史快照数据,而不是最新的数据。这意味着在快照读的过程中,即使有其他事务提交了新的更改,快照读仍然只能看到快照中的旧数据,不会受到新提交的事务的影响。
适用场景:快照读通常用于只需要读取数据,而不需要加锁的查询操作。常见的快照读操作包括:普通的 SELECT 语句(不加锁的查询)
工作原理:InnoDB 会维护一个事务快照(事务开始时的数据库版本),快照读通过 MVCC 机制来访问这个快照中的数据版本,而不是实时的最新版本。因此,快照读不会加锁,不会阻塞其他事务,也不会被其他事务的更新所影响。
例子:假设有两个事务 A 和 B:
事务 A 开始时读取了一份快照,随后事务 B 对某行进行了 UPDATE 操作并提交。
事务 A 即使再次执行 SELECT,也只能看到快照中的旧数据,而不会看到事务 B 提交的新数据。
三、区别

四、总结
(Snapshot Read)
当前读用于需要修改数据或加锁的操作,它确保读写一致性,读取最新数据,且通过锁机制避免并发冲突。
快照读用于只读的查询操作,它通过 MVCC 保证读到的始终是事务启动时的快照,避免幻读、不可重复读等问题,同时无需加锁,因此并发性能较好。
mysql 第8.6章 事务-当前读与快照读