这是一个非常深刻的问题,答案是:几乎解决了,但在一个非常特殊且罕见的边界场景下,理论上仍然可能出现幻读。 因此,严格来说,它并非被“彻底”或“100%”地解决。

下面我们来详细分解这个结论:

1. InnoDB 如何“几乎”解决了幻读?

正如之前讨论的,InnoDB 通过两种强大的武器来攻击幻读问题:

  • 对于快照读(Snapshot Read):即普通的 SELECT 语句。通过 MVCC(多版本并发控制),事务看到的是一个在它开始时创建的、静态的数据快照。无论其他事务如何插入、删除或更新,这个快照都不会改变。因此,在同一个事务内,多次执行相同的 SELECT 查询,结果集的行数绝对是一致的。这完全消除了快照读下的幻读。
  • 对于当前读(Current Read):即加锁的 SELECT ... FOR UPDATE / SELECT ... LOCK IN SHARE MODE 以及 UPDATEDELETE 语句。通过 间隙锁(Gap Lock)和临键锁(Next-Key Lock),InnoDB 不仅锁定了已有的记录,还锁住了记录之间的“间隙”,防止其他事务在这个范围内插入新的数据。这防止了其他事务的插入操作导致当前事务的当前读出现幻读

基于这两种机制,在99.9%的应用场景下,你可以认为InnoDB的可重复读隔离级别已经解决了幻读。这也是它成为MySQL默认隔离级别并能支撑绝大多数高并发业务的底气所在。

2. 那个“不彻底”的边界场景是什么?

理论上的漏洞出现在:一个事务先进行当前读(从而受间隙锁保护),然后在其内部进行快照读

让我们看一个经典的例子:

表结构:

CREATE TABLE `accounts` (`id` int(11) PRIMARY KEY,`name` varchar(50),`balance` int(11)
);
INSERT INTO accounts VALUES (1, 'Alice', 100), (5, 'Bob', 200);
-- 注意:id 2, 3, 4 目前不存在,这些就是“间隙”。

事务A (T1)

事务B (T2)

START TRANSACTION;

SELECT * FROM accounts WHERE id > 1 FOR UPDATE;
-- 这是一个当前读。它会锁定id>1的所有现有记录(id=5)和所有间隙(防止插入id=2,3,4等)。
结果: (5, 'Bob', 200)

START TRANSACTION;
INSERT INTO accounts VALUES (3, 'Charlie', 300);
-- 此操作会被事务A的间隙锁阻塞,无法完成!

SELECT * FROM accounts WHERE id > 1;
-- 这是一个快照读。MVCC保证它看不到其他事务未提交的更改,所以结果和第一次一样。
结果: (5, 'Bob', 200)

COMMIT;
-- 提交并释放锁

-- 事务A的锁释放后,事务B的INSERT操作立即成功执行。

COMMIT;

到目前为止,一切正常,幻读被成功防止。


现在,让我们制造那个边界场景:

事务A (T1)

事务B (T2)

START TRANSACTION;

SELECT * FROM accounts WHERE id > 1 FOR UPDATE;
结果: (5, 'Bob', 200)

START TRANSACTION;
INSERT INTO accounts VALUES (3, 'Charlie', 300);
-- 同样被阻塞

...

...

-- 关键一步:事务A自己执行一个插入操作,这个操作恰好也落在被它锁住的间隙里

INSERT INTO accounts VALUES (2, 'David', 400);
-- 这个操作是允许的!一个事务总是可以修改自己被锁住的数据。

-- 此时,由于事务A执行了DML操作(INSERT),InnoDB会隐式地推进它的快照时间点(在某些版本和场景下),以保证事务自身能看到自己刚做的修改。

SELECT * FROM accounts WHERE id > 1;
-- 再次进行快照读。此时快照可能已经被更新,它不仅能看到自己刚插入的id=2的记录,也可能看到之前被它阻塞、但现已提交的事务B插入的id=3的记录!

结果: (2, 'David', 400), (3, 'Charlie', 300), (5, 'Bob', 200)

COMMIT;

分析:
在同一个事务A内,两次执行 SELECT ... WHERE id > 1

  • 第一次返回 1 行。
  • 第二次返回 3 行。
  • 行数发生了变化,这符合幻读的定义。

结论

  1. 是否彻底解决? 。从理论和技术完备性的角度,InnoDB的可重复读隔离级别存在一个极其罕见的边界场景(自身DML操作推进快照并看到其他已提交的插入),使得幻读仍然可能发生。
  2. 是否值得担心? 几乎不需要。这个场景需要非常特殊的操作序列(先加锁读,然后自己或他人恰好操作同一个间隙,最后自己再读),在绝大多数真实业务逻辑中几乎不会有意或无意地这样编写代码。
  3. 实践中的选择? 你可以放心地将InnoDB的可重复读隔离级别视为解决了幻读问题。如果您的应用处于那0.1%的极端场景且对一致性有极致要求,解决方案通常是:
    • 使用串行化(SERIALIZABLE)隔离级别:彻底解决,但性能代价最高。
    • 在需要绝对精确的地方显式使用 SELECT ... FOR UPDATE:通过持续加锁来保证当前读的一致性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/921462.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921462.shtml
英文地址,请注明出处:http://en.pswp.cn/news/921462.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零开始的云计算生活——第五十八天,全力以赴,Jenkins部署

目录 一.故事背景 二.安装Jenkins必要插件 1.安装Publish Over SSH 2.安装maven integration插件 3. 配置jenkins并发执行数量 4. 配置邮件地址 三. 基于Jenkins部署PHP环境 1. 下载ansible插件 2. 下载ansible应用 3. 构建项目 ​编辑 使用Jenkins账户生成ssh密钥 …

串口HAL库发送问题

想了很久,不知道该标题起的是否合适,该篇Blog用于记录在使用HAL库的USART模块时实际遇到的一个涉及发送方式的问题,用于提醒自身同时也希望能帮到各位。程序问题叙述先来看一段代码:void CusUSART_SendByte_IT( uint8_t Byte ) { …

CUDA默认流的同步行为

默认流 对于需要指定 cudaStream_t参数的 cuda API,如果将 0作为实参传入,则视为使用默认流;对于不需要指定 cudaStream_t参数的 cuda API,则也视为使用默认流。 在 cuda中,默认流有两种类型,一种是 legacy…

「数据获取」《中国电力统计年鉴》(1993-2024)(含中国电力年鉴)

01、数据简介一、《中国电力统计年鉴》作为全面系统反映中国电力领域发展状况的权威性年度统计资料,涵盖了电力建设、生产、消费及供需等全链条关键信息。其编制工作有着深厚的历史积淀,可追溯至 20 世纪 50 年代,历经数十年的积累与完善&…

《AI大模型应知应会100篇》第68篇:移动应用中的大模型功能开发 —— 用 React Native 打造你的语音笔记摘要 App

📱 第68篇:移动应用中的大模型功能开发 —— 用 React Native 打造你的语音笔记摘要 App 🎯 核心目标:零门槛集成大模型,5步开发跨平台智能功能 🧩 适用人群:前端开发者、产品经理、独立开发者 …

FPGA ad9248驱动

ad9248的最高时钟频率65mhz,采用cmos3.3v电压的并行io接口,做成电子模块后一般为双通道adc,有两个对外输出时钟cha_clk与chb_clk,一个并行输入端口,14分辨率的ddr_data,其模块逻辑如下,首先向ad…

Spring MVC 处理请求的流程

Spring MVC 处理请求的流程流程步骤详解第1步:发起请求 (HTTP Request)第2步:映射处理器 (Handler Mapping)第3步:获取适配器 (Handler Adapter)第4步:执行拦截器前置处理 (Interceptors - preHandle)第5步:真正调用处…

敏捷scrum管理实战经验总结

1.敏捷 敏捷的构成 敏捷由实践来源、应用场景、组织文化、领导力、团队、需求、管理、技术、质量、度量、交付、过程改进、大型项目组合管理以及受监管行业中的敏捷等构成 敏捷开发的特点 短发布周期小批量的方式、开展从需求到实现的开发工作高层级的预先规划结合详细的即时规…

南科大适应、协同与规划的完美融合!P³:迈向多功能的具身智能体

作者:Shengli Zhou1^{1}1, Xiangchen Wang1^{1}1, Jinrui Zhang1^{1}1, Ruozai Tian2^{2}2, Rongtao Xu2,3^{2,3}2,3, Feng Zheng1,2^{1,2}1,2单位:1^{1}1南方科技大学,2^{2}2时空智能,3^{3}3穆罕默德本扎耶德人工智能大学论文标题…

自动化流水线

import React, { useState, useEffect } from ‘react’; import { ChevronRight, CheckCircle, Circle, AlertCircle, Clock, Play, Pause, Settings, Code, Server, Shield, Database, Globe, Zap, FileText, Users, GitBranch, Package, Monitor, ChevronDown } from ‘luci…

【高等数学】第十一章 曲线积分与曲面积分——第三节 格林公式及其应用

上一节:【高等数学】第十一章 曲线积分与曲面积分——第二节 对坐标的曲线积分 总目录:【高等数学】 目录 文章目录1. 格林公式2. 平面上曲线积分与路径无关的条件3. 二元函数的全微分求积4. 曲线积分的基本定理1. 格林公式 单连通与复连通区域 设 DDD …

Boost电路:平均状态空间建模

电路特征介绍如图所示是一个非理想情况下的boost电路,其中L1L_{1}L1​和RL1R_{L1}RL1​是分别是电感和串联电阻;C1C_{1}C1​和RC1R_{C1}RC1​是输出电容和串联电阻;Q1Q_{1}Q1​是MOS管,其导通电阻是RonR_{on}Ron​;D1D…

免费网站模板/网站模板建站的优势/如何下载网站模板搭建网站?

在网站建设领域,“网站模板” 是降低技术门槛、提升建站效率的核心工具,尤其适合非专业开发者或追求低成本、快上线的需求场景。下面从定义、核心优势两方面展开详细解析,帮助你全面理解其价值。 一、什么是网站模板? 网站模板&am…

【MATLAB例程】平面上的组合导航例程,使用EKF融合IMU和GNSS数据,8维状态量和2维观测量,附代码下载链接

文章目录程序详解概述系统架构核心数学模型性能评估算法特点运行结果MATLAB源代码程序详解 概述 本代码实现基于扩展卡尔曼滤波器(EKF)的二维组合导航系统,融合IMU(惯性测量单元)和GNSS(全球导航卫星系统…

react生命周期,详细版本

React 组件的生命周期分为三个阶段:挂载(Mounting)、更新(Updating) 和 卸载(Unmounting)。以下是类组件生命周期的详细说明(基于 React 16.3+ 版本): 一、挂载阶段(Mounting) 组件实例被创建并插入 DOM 时的流程: constructor(props) ○ 用途:初始化状态(this…

腾讯最新开源HunyuanVideo-Foley本地部署教程:端到端TV2A框架,REPA策略+MMDiT架构,重新定义视频音效新SOTA!

一、模型介绍HunyuanVideo-Foley 是腾讯混元团队在2025年8月底开源的一款端到端视频音效生成模型。它旨在解决AI生成视频“有画无声”的痛点,通过输入视频和文本描述,就能自动生成电影级别的同步音效,显著提升视频的沉浸感。它是专为视频内容…

计算机原理(二)

计算机原理系列 欢迎大家关注「海拉鲁知识大陆」 多交流不迷路 计算机原理(一) 继续上一篇计算机原理(一)深入了解程序执行部分,进一步说说程序在冯诺依曼模型上如何执行。如果没有了解的童鞋可以查看我上一篇文章。…

【设计模式】 工厂方法模式

系列文章目录 文章目录系列文章目录需要了解工厂制造细节吗?简单工厂模式实现工厂方法模式的实现简单方法? 工厂方法?总结需要了解工厂制造细节吗? 我们在前面的文章中为大家介绍了简单工厂模式,我们知道 简单工厂模式…

详解 Java 中的 CopyOnWriteArrayList

目录 【1】CopyOnWriteArrayList 简介 【2】核心原理 1.底层数据结构 2.写时复制机制 【3】CopyOnWriteArrayList常用方法及实例 1.添加元素方法 add () 2.获取元素方法 get () 3.删除元素方法remove() 【4】优缺点分析 【5】适用场景 【6】总结 【1】CopyOnWriteAr…

新手SEO优化快速起步教程

本教程专为SEO新手设计,帮助您快速上手优化工作。我们将一步步带您了解基础概念,包括高效挖掘关键词的方法、内容优化的核心技巧,以及网站基础设置的关键步骤。后续还会讲解提升排名的实用策略、如何监控效果并进行调整,确保您能系…