可重复读(Repeatable Read)隔离级别下幻读产生的原因

幻读(Phantom Read) 是指在一个事务中,两次相同的范围查询返回了不同数量 的行,主要由于其他事务插入新行导致。

产生幻读的核心原因:

1. 快照读 vs 当前读的混合使用
sql 复制代码
-- 可重复读下,普通SELECT是快照读,基于MVCC版本链
SELECT * FROM users WHERE age > 20; -- 快照读,使用事务开始时的快照

-- 但某些操作会触发当前读
UPDATE users SET status = 1 WHERE age > 20; -- 当前读,看到最新提交的数据
SELECT * FROM users WHERE age > 20 FOR UPDATE; -- 当前读,加锁
2. MVCC的局限性
  • MVCC保证已存在的行读取一致性

  • 但无法阻止其他事务插入新的行

  • 事务开始时创建ReadView,只记录当时已存在的行版本

3. 锁机制的缺失

在标准SQL规范中,可重复读级别:

  • 只对已存在的行加锁(行锁)

  • 不对不存在的行(间隙)加锁

  • 因此其他事务可以插入满足条件的新行

实际示例:

sql 复制代码
-- 事务A
START TRANSACTION;
-- 第一次查询:返回id为1,2,3的3条记录
SELECT * FROM users WHERE id BETWEEN 1 AND 5;

-- 此时事务B插入id=4的新记录并提交
INSERT INTO users(id, name) VALUES (4, 'new_user');
COMMIT;

-- 事务A再次查询(可重复读应返回相同3条记录)
SELECT * FROM users WHERE id BETWEEN 1 AND 5; -- 仍然只看到id 1,2,3

-- 但事务A执行更新操作时
UPDATE users SET status = 1 WHERE id BETWEEN 1 AND 5;
-- 更新会作用到id=4的行(因为更新是当前读)
-- 然后事务A再次查询,就会看到4条记录 ← 这就是幻读

MySQL InnoDB的特殊处理

MySQL通过Next-Key Locking机制在可重复读级别避免了幻读:

sql 复制代码
SELECT * FROM users WHERE age > 20 FOR UPDATE;
-- InnoDB会锁住age>20的整个范围(间隙锁+行锁)
-- 其他事务无法插入age>20的新行

总结表格:

隔离级别 脏读 不可重复读 幻读
读未提交
读已提交
可重复读 可能发生
串行化

关键点

  • 幻读专指新插入的行

  • 可重复读能防止已存在行的修改,但不能防止新行的插入

  • 实际应用中可通过SELECT ... FOR UPDATE加间隙锁来避免

相关推荐
其实防守也摸鱼1 小时前
运维--学习阶段问题解答(1)(自测)
linux·运维·服务器·数据库·学习·自动化·命令模式
懒鸟一枚1 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
龙仔7252 小时前
SQL Server 创建只读账号完整操作(分两种场景:SSMS图形界面 + T-SQL脚本)
数据库·sql·oracle
霁月的小屋2 小时前
生产环境中的事务实践——银行系统上线记(四)
数据库
Database_Cool_2 小时前
AI 应用数据底座首选:阿里云 PolarDB 为大模型 RAG 提供一体化支撑
数据库·阿里云
玖玥拾2 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#
IvorySQL4 小时前
PG 日报|社区讨论重构 pg_hba 配置文件格式
数据库·人工智能·postgresql·重构·ivorysql
逝水无殇4 小时前
C# 文件的输入与输出详解
开发语言·数据库·后端·c#
渣渣灰飞4 小时前
MySQL 系统学习 第五阶段:企业级 MySQL 实战开发 第二章:RBAC 权限系统设计
android·学习·mysql