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

为什么MySQL可重复读级别不能完全避免幻读

可重复读隔离级别通过 MVCC 快照读避免不可重复读,而阻止幻读依赖于在“当前读”时加的间隙锁;因为快照读不加锁,间隙锁只在执行当前读时才可能会生效,——所以 RR 无法 100% 消除幻读。

一致性读(快照读)

基于事务的 Read View(MVCC 快照),不加锁,读到的是事务启动时或语句启动时的可见版本。

/*一致性读(快照读)
*/
-- 普通 SELECT
SELECT * FROM account WHERE id = 1;
-- 范围查询
SELECT * FROM account WHERE balance > 1000;
-- 聚合查询
SELECT COUNT(*) FROM account WHERE balance > 1000;

当前读

读取当前已提交的数据并在读取时加锁,用于保证随后的写操作安全或防幻读。

/*当前读
*/-- 排它锁(锁住记录 + 间隙)
SELECT * FROM account WHERE id BETWEEN 10 AND 20 FOR UPDATE;-- 共享锁(锁住记录 + 间隙,但允许其他事务读取)
SELECT * FROM account WHERE id BETWEEN 10 AND 20 LOCK IN SHARE MODE;-- 更新指定范围的记录(隐式当前读 + 加锁)
UPDATE account SET balance = balance - 100 WHERE id BETWEEN 10 AND 20;-- 删除操作(隐式当前读 + 加锁)
DELETE FROM account WHERE balance < 500;

要点说明

MVCC 与快照读的本质:

RR 下普通 SELECT 使用事务启动时的 Read View(快照),读的是历史版本,不受后来提交的写影响,快照读本身不加锁,因此并不会阻止并发事务插入新行(这些新行对快照不可见,但如果随后做当前读就可能看到它们)。

间隙锁 / Next-Key Lock 的作用与时机:

为防幻读,InnoDB 在执行当前读(SELECT ... FOR UPDATE、UPDATE、DELETE)时对记录及其间隙加锁(next-key lock = 记录锁 + 间隙锁)。

加锁是在执行当前读时发生,只能阻止之后的插入,无法阻止在此之前已经插入的行。

索引依赖与锁覆盖问题:

间隙锁基于索引范围;如果查询未走合适索引或条件复杂,锁可能覆盖不全或退化,导致仍有插入不被拦截,从而出现幻读。

快照读与当前读混合的语义差异:

事务内先做快照读(看到旧数据),随后做当前读(看到最新并加锁),两者语义不同,可能产生“集合变化”的感受,即幻读现象仍然可能出现。

性能与一致性的权衡:

InnoDB 不会无差别地锁住所有间隙(会权衡并发性能),因此在某些场景下不会或不能完全阻止所有可能的幻读。

RR下发生幻读的示例

-- T1: 第一次范围查询
SELECT * FROM account WHERE balance > 1000;
-- 普通 SELECT(快照读 / 一致性读)
-- 不加锁,不触发间隙锁
-- 只能看到事务启动时的快照-- T2: 插入新记录
INSERT INTO account(id, balance) VALUES (1001, 2000);
-- 可以成功插入,因为 T1 的第一次查询没有加锁-- 回到 T1: 第二次查询
SELECT * FROM account WHERE balance > 1000 FOR UPDATE;
-- 当前读,此时才会触发锁(排它锁 + 间隙锁)
-- 会读取最新数据,包括 T2 插入的记录,就会看到新增行 → 发生幻读
-- 如果后面再有事务对已经锁住的区域进行写操作,就会阻塞

文章转载自:

http://8a3rjs9P.nwqyq.cn
http://ZqBkpkWs.nwqyq.cn
http://xOqRLglb.nwqyq.cn
http://ElUfTUkY.nwqyq.cn
http://3Hbs5R43.nwqyq.cn
http://9pXsQ2qd.nwqyq.cn
http://JBbQQFsx.nwqyq.cn
http://0TxsKLPB.nwqyq.cn
http://h5cBjDE3.nwqyq.cn
http://5JKiBTY7.nwqyq.cn
http://ZJM4hUdw.nwqyq.cn
http://Uas4tcON.nwqyq.cn
http://1PaTusHl.nwqyq.cn
http://1V8jWxC6.nwqyq.cn
http://A1s49Otm.nwqyq.cn
http://s3R2xThD.nwqyq.cn
http://00HrH2Wn.nwqyq.cn
http://TqTLCopr.nwqyq.cn
http://l1eS97kz.nwqyq.cn
http://qldnuUTL.nwqyq.cn
http://EAnsMfyV.nwqyq.cn
http://KNzOcodR.nwqyq.cn
http://0kWCpvSK.nwqyq.cn
http://uWS7BjNZ.nwqyq.cn
http://y8iy1mWZ.nwqyq.cn
http://fKzNysoQ.nwqyq.cn
http://XhbrX9EI.nwqyq.cn
http://ujYOYhKG.nwqyq.cn
http://116kv4Pg.nwqyq.cn
http://qLhA9hKz.nwqyq.cn
http://www.dtcms.com/a/368420.html

相关文章:

  • Gradle Task 进阶:Task 依赖关系、输入输出、增量构建原理
  • 串口通信基础知识
  • webshell及冰蝎双击无法打开?
  • Doris 数据仓库例子
  • 从零构建企业级LLMOps平台:LMForge——支持多模型、可视化编排、知识库与安全审核的全栈解决方案
  • 如何根据Excel数据表生成多个合同、工作证、录取通知书等word文件?
  • Highcharts 数据源常见问题解析:连接方式、格式处理与性能优化指南
  • T06_RNN示例
  • 【Android】Room数据库的使用
  • CoolGuard风控系统配置评分卡、权重策略|QLExpress脚本
  • 【FastDDS】Layer Transport ( 02-Transport API )
  • 确保 SQL Server 备份安全有效的最佳实践
  • 盘点完今年CoRL最火的VLA论文,发现最强的机器人,竟是用“假数据”喂大的
  • 新闻丨重庆两江新区党工委副书记、管委会主任许宏球一行莅临华院计算考察指导
  • 基于YOLO目标检测模型的视频推理GUI工具
  • latex公式符号与字体
  • SQL Server事务隔离级别
  • SQL高效处理海量GPS轨迹数据:人员gps轨迹数据抽稀实战指南
  • 查询语言的进化:SQL之后,为什么是GQL?数据世界正在改变
  • 概念 | C标准库STL,C运行时库CRT
  • JAiRouter 配置文件重构纪实 ——基于单一职责原则的模块化拆分与内聚性提升
  • ZooKeeper架构深度解析:分布式协调服务的核心设计与实现
  • ResNet 迁移学习---加速深度学习模型训练
  • Django REST framework:SimpleRouter 使用指南
  • Vue3 频率范围输入失焦自动校验实现
  • 删除元素(不是删除而是覆盖)快慢指针 慢指针是覆盖位置,快指针找元素
  • 代码随想录算法训练营第三天| 链表理论基础 203.移除链表元素 707.设计链表 206.反转链表
  • 结合机器学习的Backtrader跨市场交易策略研究
  • 前端开发vscode插件 - live server
  • 码农的“必修课”:深度解析Rust的所有权系统(与C++内存模型对比)