当前位置: 首页 > news >正文

可重复读(Repeatable Read)能解决幻读吗?

一、问题背景

在数据库事务中,常见的并发问题有:

  • 脏读(Dirty Read):读到未提交的数据。
  • 不可重复读(Non-Repeatable Read):两次读取同一行数据结果不一致。
  • 幻读(Phantom Read):同一事务中两次查询的结果集行数不一致。

幻读定义:

在一个事务中,多次执行相同条件的查询时,第二次查询结果中出现了第一次没有的“新行”,或者一些行消失了。

示例:

-- 事务 A
START TRANSACTION;
SELECT * FROM orders WHERE amount > 100;  -- 返回 3 行
-- 此时事务 B 插入一条 amount=200 的记录并提交
SELECT * FROM orders WHERE amount > 100;  -- 返回 4 行(幻读)

二、可重复读(Repeatable Read)能否解决幻读?

1. SQL 标准中的定义

  • Repeatable Read:保证事务中对同一行的多次读取结果一致,避免不可重复读,但不保证避免幻读
  • Serializable:串行化,所有事务顺序执行,完全避免幻读。

2. MySQL InnoDB 的实现

MySQL 的 默认隔离级别是 Repeatable Read,并且 InnoDB 在 Repeatable Read 下可以避免幻读,原因是 使用了 Next-Key Lock(记录锁 + 间隙锁)

为什么能避免幻读?
  • MVCC(快照读)

    • 普通 SELECT 使用 一致性读,通过事务开始时的 Read View 提供稳定结果,不会看到新插入的数据。
    • 所以在相同事务中,多次普通查询不会出现幻读。
  • Next-Key Lock(当前读)

    • 如果事务执行 加锁操作(SELECT … FOR UPDATE / UPDATE / DELETE),InnoDB 会对 索引记录 + 相邻间隙 加锁,防止其他事务插入新行。
    • 这避免了幻读问题。

三、Repeatable Read 与幻读的关系

情况 1:普通查询(快照读)

START TRANSACTION;
SELECT * FROM orders WHERE amount > 100; -- 第一次查询
-- 事务 B 插入新行并提交
SELECT * FROM orders WHERE amount > 100; -- 第二次查询,仍然返回旧结果(MVCC)

结果:不会出现幻读,因为读取的是事务开始时的快照。

情况 2:加锁查询(当前读)

START TRANSACTION;
SELECT * FROM orders WHERE amount > 100 FOR UPDATE;
-- 事务 B 尝试插入一条 amount=200 的记录,会被阻塞,直到事务 A 提交

结果:不会出现幻读,因为 Next-Key Lock 锁定了间隙。


四、Next-Key Lock 机制详解

Next-Key Lock = 记录锁(Record Lock)+ 间隙锁(Gap Lock)

  • 记录锁:锁定具体行,防止修改。
  • 间隙锁:锁定两个记录之间的间隙,防止插入。

示意图(假设索引列值为 10、20、30):

锁定范围:
(10)---(20)---(30)
事务 A 锁定 (10,20) 间隙,其他事务无法在 10 和 20 之间插入新记录。

五、MySQL 四种隔离级别与幻读对比

隔离级别脏读不可重复读幻读
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ❌(InnoDB 通过 Next-Key Lock 避免)
SERIALIZABLE

注意:InnoDB 的 Repeatable Read 已经避免幻读,但在其他数据库(如 Oracle),Repeatable Read 不能避免幻读,必须用 Serializable。


六、为什么 InnoDB Repeatable Read 能避免幻读?

  1. 普通查询使用 MVCC 快照,不会读到其他事务插入的新行。
  2. 当前读(加锁语句)使用 Next-Key Lock,阻止其他事务在范围内插入新行。

七、面试高频问答

Q1:幻读和不可重复读区别?

  • 不可重复读:同一行数据两次读取结果不同(因为更新)。
  • 幻读:多次查询结果集行数不同(因为插入或删除)。

Q2:MySQL 默认隔离级别能避免幻读吗?

  • ,因为 InnoDB 在 Repeatable Read 下用 MVCC + Next-Key Lock 避免幻读。

Q3:Next-Key Lock 是什么?

  • 记录锁 + 间隙锁,锁定行和相邻间隙,防止插入,避免幻读。

Q4:Serializable 和 Repeatable Read 区别?

  • Serializable 通过 强制事务串行执行 避免所有并发问题,性能差。
  • InnoDB 的 Repeatable Read 通过 MVCC + 锁 实现高性能,且避免幻读。

八、总结

  • SQL 标准:Repeatable Read 不能完全避免幻读。
  • MySQL InnoDB:Repeatable Read + MVCC + Next-Key Lock 可以避免幻读。
  • 应用场景:默认隔离级别 Repeatable Read 足够安全,除非业务必须串行化。
http://www.lryc.cn/news/610457.html

相关文章:

  • 【unitrix】 7.1 二进制位加法(bit_add.rs)
  • Minio部署和客户端使用 - 版本 2025-05-24T17-08-30Z
  • 县级融媒体中心备份与恢复策略(精简版3-2-1架构)
  • Javascript面试题及详细答案150道(046-060)
  • Linux 交换空间管理
  • 15个命令上手Linux!
  • 力扣top100--哈希
  • PandasAI连接LLM对MySQL数据库进行数据分析
  • 【笔记】重学单片机(51)(下)
  • ArcGIS的字段计算器生成随机数
  • 数据库提权
  • 并发编程常用工具类(下):CyclicBarrier 与 Phaser 的协同应用
  • (论文速读)RMT:Retentive+ViT的视觉新骨干
  • Hadoop HDFS 3.3.4 讲解~
  • 嵌入式知识篇---闪存
  • mysql 数据库系统坏了,物理拷贝出数据怎么读取
  • Deepoc 赋能送餐机器人:从机械执行到具身智能的革命性跨越
  • JavaScript 中的流程控制语句详解
  • 机器学习实战:逻辑回归深度解析与欺诈检测评估指标详解(二)
  • Redis缓存详解及常见问题解决方案
  • MySQL 基本操作入门指南
  • MCP进阶:工业协议与AI智能体的融合革命
  • 使用 SecureCRT 连接华为 eNSP 模拟器的方法
  • typeof和instanceof区别
  • Linux学习记录(八)文件共享
  • 认识pytorch与pytorch lightning
  • BackgroundTasks 如何巧妙驾驭多任务并发?
  • 我的创作纪念日____在 CSDN一年来的成长历程和收获
  • openvela之内存管理
  • Linux 磁盘管理与分区配置