快照读和当前读

在 MySQL 的 InnoDB 存储引擎中,快照读(Snapshot Read)和当前读(Current Read)是两种不同的读取方式,它们在处理并发事务时有不同的行为和应用场景。

快照读(Snapshot Read)

快照读是一种一致性非锁定读,它通过多版本并发控制(MVCC)机制来实现。这意味着即使在读取数据时有其他事务正在修改数据,快照读也会返回一个一致性的视图,不会被其他事务的更改所影响。

特点

  • 无锁读取:不会加锁,允许并发读取。
  • 一致性视图:读取的数据是事务开始时刻的数据快照,即使其他事务正在对数据进行修改。
  • 避免锁冲突:适合高并发的读操作,减少锁争用。

应用场景

  • 高并发读操作:需要读取大量数据且希望避免锁争用的场景。
  • 事务中的读操作:读取数据时希望看到一致性的视图,而不是最新的数据。

示例

事务 A 和事务 B 并发进行:

1
2
3
4
5
6
7
8
9
10
11
-- 事务 A
START TRANSACTION;
SELECT * FROM employees WHERE dept_id = 1; -- 快照读

-- 事务 B
START TRANSACTION;
UPDATE employees SET age = age + 1 WHERE dept_id = 1;
COMMIT;

-- 事务 A 提交
COMMIT;

事务 A 的 SELECT 语句是快照读,它读取的是事务开始时的视图,不受事务 B 的 UPDATE 操作影响。

即使有其他事务在修改 employees 表中的数据,上述查询仍然会返回事务开始时的视图。

当前读(Current Read)

当前读是一种锁定读,它会读取最新的数据,并且在读取数据时会对读取的数据加锁,以确保数据的独占访问。

特点

  • 锁定读取:读取的数据会加锁,以确保其他事务不能同时修改这些数据。
  • 读取最新数据:读取的数据是最新的数据,而不是事务开始时的数据快照。
  • 防止幻读:适用于需要确保数据一致性和完整性的场景。

应用场景

  • 更新操作:需要读取最新数据并对其进行更新的场景。
  • 防止并发修改:需要确保数据在读取和更新之间不会被其他事务修改的场景。

示例

以下操作是当前读:

1
2
SELECT * FROM employees WHERE dept_id = 1 FOR UPDATE;  -- 排它锁
SELECT * FROM employees WHERE dept_id = 1 LOCK IN SHARE MODE; -- 共享锁

事务 A 和事务 B 并发进行:

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 事务 A
START TRANSACTION;
SELECT * FROM employees WHERE dept_id = 1 FOR UPDATE; -- 当前读

-- 事务 B
START TRANSACTION;
UPDATE employees SET age = age + 1 WHERE dept_id = 1; -- 被阻塞
COMMIT;

-- 事务 A 提交
COMMIT;

-- 事务 B 继续

事务 A 的 SELECT … FOR UPDATE 是当前读,它会对读取的数据加锁,阻止事务 B 在事务 A 提交之前对相同数据进行更新。

上述查询会加锁,以确保其他事务在当前事务完成之前不能修改或插入相关的数据。

对比

读方式 特点 应用场景 示例
快照读 无锁读取,一致性视图 高并发读操作,事务中的读操作 SELECT * FROM employees WHERE dept_id = 1;
当前读 锁定读取,读取最新数据,防止幻读 更新操作,防止并发修改 SELECT * FROM employees WHERE dept_id = 1 FOR UPDATE;

总结

  • 快照读:通过 MVCC 提供一致性视图,不加锁,适合高并发读操作。
  • 当前读:通过加锁确保读取最新数据,适合需要防止并发修改的更新操作。

根据具体的应用场景和需求选择合适的读取方式,可以平衡系统的并发性能和数据一致性。


快照读和当前读
https://randzz.cn/b4a6fe94d4b1/快照读和当前读/
作者
Ezreal Rao
发布于
2024年7月5日
许可协议