什么是幻读?

ANSI SQL 隔离级别中的 幻读(Phantom Read) 是指在同一事务内,由于其他事务插入或删除了符合当前事务查询条件的数据行,导致同一查询多次执行时返回不同的结果集。幻读的核心是 结果集的行数发生变化(新增或消失的行),而不仅仅是同一行数据的值被修改。


幻读的本质

  • 针对范围查询:幻读通常发生在范围查询(如 WHERE age > 20)或全表扫描时。
  • 新增或删除的行:其他事务插入或删除的行如果符合当前事务的查询条件,会导致当前事务后续查询的结果集出现“幻觉”。
  • 与不可重复读的区别
    • 不可重复读:同一行数据的值被其他事务修改(如 UPDATE)。
    • 幻读:结果集中新增或删除了行(如 INSERTDELETE)。

幻读是否仅针对插入?

不完全正确。虽然幻读最常见的原因是其他事务插入新行,但以下两种操作也可能导致幻读:

  1. 插入(INSERT):新增符合查询条件的行。
  2. 删除(DELETE):删除符合查询条件的行。
  3. 更新(UPDATE):在某些场景下,更新操作可能间接导致幻读(见下文)。

示例分析

场景 1:插入新行导致幻读
-- 事务A(隔离级别:可重复读)
BEGIN TRANSACTION;
SELECT * FROM users WHERE age > 25; -- 返回 2 条记录

-- 事务B 插入一条 age=30 的新记录并提交
INSERT INTO users (id, name, age) VALUES (3, 'Charlie', 30);
COMMIT;

-- 事务A 再次查询
SELECT * FROM users WHERE age > 25; -- 返回 3 条记录(出现幻读)
COMMIT;
场景 2:更新导致幻读(特殊情况)

如果其他事务通过 UPDATE 操作修改数据,使得某些行从“不符合条件”变为“符合条件”,也可能导致幻读:

-- 初始数据
INSERT INTO users (id, name, age) VALUES (4, 'David', 20);

-- 事务A(隔离级别:可重复读)
BEGIN TRANSACTION;
SELECT * FROM users WHERE age > 25; -- 返回 2 条记录

-- 事务B 更新 David 的年龄为 30 并提交
UPDATE users SET age = 30 WHERE id = 4;
COMMIT;

-- 事务A 再次查询
SELECT * FROM users WHERE age > 25; -- 可能返回 3 条记录(出现幻读)
COMMIT;

为什么更新可能导致幻读?

  • 可重复读(Repeatable Read) 隔离级别下,ANSI SQL 标准允许幻读,但某些数据库(如 MySQL)通过 MVCC(多版本并发控制)锁机制 规避了部分幻读。
  • 如果事务A的查询基于快照(如 MySQL 的 RR 级别),则不会看到事务B提交的更新后的数据,因此不会出现幻读。
  • 如果事务A的查询是“当前读”(如 SELECT ... FOR UPDATE),则可能看到事务B提交的更新后的数据,导致幻读。

总结

  1. 幻读主要针对插入和删除,但更新操作也可能间接导致幻读(如数据从“不可见”变为“可见”)。
  2. ANSI SQL 标准 中,可重复读隔离级别允许幻读,而串行化(Serializable)隔离级别通过锁机制彻底避免幻读。
  3. 实际数据库的实现差异
    • MySQL 的可重复读(通过 MVCC)可以避免大部分幻读。
    • PostgreSQL 的可重复读严格遵循 ANSI 标准,允许幻读,需升级到串行化隔离级别解决。

关键结论

  • 幻读不仅是插入导致,删除和更新(间接)也可能引发。
  • 是否发生幻读取决于 隔离级别的具体实现(如快照隔离、锁机制等)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值