臭名昭著aTrust隔离计划1.臭名昭著aTrust隔离计划2.VPN原理与aTrust隔离网络实践3.docker-easyconnect到底做了什么4.TUN(tunnel-隧道-虚拟网卡)模式
个人项目
personal(个人展示)GitHub Actions 自动部署个人展示项目
基于Quartz搭建的个人博客1.Quartz个人博客使用教程2.使用 rsync 增量部署 Quartz 博客3.使用 GitHub Actions 自动部署 Quartz 博客5.域名绑定6.CDN加速7.Google 搜索收录排查:为什么关键词搜得到别人,却搜不到我的网站?Obsidian、双向链接与知识图谱
架构设计
分布式分布式事务RPC原理
旅行
行程攻略青岛三日游行程攻略
前端
NginxNginx配置与反向代理入门
Nodenpm与npx的区别
数据库
mysql01.MySQL基础语法与约束02.MySQL数据库类型03.MySQL多表查询04.MySQL 索引05.MySQL 事务06.MySQL 隔离级别07.MySQL MVCC08.MySQL 锁09.EXPLAIN10.慢查询与 SQL 优化
mysql面试题01.索引问题02.事务与隔离级别03.锁机制04.存储引擎与性能优化05.用户权限、字符集与备份恢复
mysql实战01.EXPLAIN实战02.测试环境菜单误删排查与恢复03.MySQL IN 详解
网络
网络安全1.无线监听网卡苹果M系列虚拟机安装Kali Linux教程3.kali怎么使用RTL8812AU4.kali基础命令
网络基础进程之间怎样通过网络传递数据
网址常用网址
中间键
esElasticsearch 入门
mq
RabbitMQRabbitMQ高级RabbitMQ基础
1. MQ 基础2. MQ 核心角色与代码对应3. MQ Consumer Group 与消费模式4. SOFAMQ 账户变更代码实践5. MQ 可靠性问题6. 消息幂等
redis缓存击穿、穿透与雪崩Redis 分布式锁Redis 缓存问题Redis 数据结构
AI
使用说明
第三方插件&技能简介Archify使用与安装指南geekgeekRun使用OfferFlow使用指南Ponytail使用指南Skills Manager使用指南
CodexCodex CLI与IDE区别及使用指南Codex Hook单独配置与提交通知Codex MCP安装与使用指南Codex第三方插件安装与使用指南
Agent开发0-学习路线1.LLM、Token、上下文窗口与模型参数2.大模型 API、请求参数与响应结构3.Spring AI ChatClient4.Prompt、System Prompt、Prompt 模板6.结构化输出、JSON Schema7.SSE 流式响应8.会话 ID、聊天记录、Redis9.超时、重试、限流、降级10.*完成可运行聊天接口11.Function Calling、Tool Calling 原理12.用 Java 方法定义 Tool13.工具参数设计和校验14.实现订单查询工具15.实现物流查询工具16.实现库存查询工具17.多个工具自动选择18.工具异常、超时、重试
diy主机
主机零件学习1.CPU2.主板3.内存4.显卡5.硬盘6.散热7.风扇8.机箱热门型号价格表
捡垃圾diy-13600kf+5060diy-14600kf+5070
English高频词汇英文基础语法简单句子音标
GitGit常用命令Sublime Merge 使用指南
Java
工具库Caffeine本地缓存Reactor教程
工作实践如何使用@Async线程池使用与排查线上服务 CPU 使用率过高排查压测下RPC接口大量失败排查记录
基础1.HashMap2.ConcurrentHashMap3.HashSet4.final5.static6.volatile7.AtomicInteger8.String动态代理反射锁与线程同步线程注解
面试题1.HashMap 存储在方法内是线程安全的吗2.ArrayList参数传递与引用重新赋值3.== 和 equals 的区别、hashcode4.重载和重写的区别5.String、StringBuffer、StringBuilder区别及使用场景6.接口和抽象类7.ArrayList 与 LinkedList 的区别和扩容机制8.HashMap 和 Hashtable 的区别及底层实现9.Object 和 Objects 的区别10.ThreadLocal的原理和使用场景11.字节码是什么及作用12.Java类加载器有哪些13.双亲委派模型14.Java异常体系15.GC是什么16.GC如何判断对象可以被回收
面试总结0.HR面试模板1.面试一2.面试二3.面试三笔试
网络与 IO(黑马程序员-纯理论)01-网络编程基础02-IO模型与零拷贝03-BIO04-NIO基础与缓冲区05-NIO通道与选择器06-AIO
juc00-目录01-进程与线程02-线程同步与通信03-并发设计模式04-Java内存模型05-CAS与原子类06-ThreadLocal07-阻塞队列08-线程池使用与原理09-任务调度10-ForkJoin与享元模式11-AQS12-ReentrantLock13-读写锁14-并发协作工具15-ConcurrentHashMap16-CopyOnWrite与同步容器17-SkipListMap18-非阻塞队列
juc(工作常见)Java并发编程三个重点拆解
jvm1. JVM运行时数据区
Spring1.Spring IoC、DI与构造方法注入CGLIB、Byte Buddy 与 Spring AOPSpring 常用注解详解Spring Bean 生命周期
Spring MVC异常处理机制
linux常用命令
mac快捷键终端常用操作
python
基础01.Python是什么,为什么要安装Python02.Python项目中.venv是什么03.Python基础语法
基础实战sql替换
HTTPXHRMS员工详情接口调用(Python HTTPX)
windowswindows激活

一、💡 隔离级别到底在解决什么

一句话理解

多个事务同时操作数据库时,隔离级别规定事务之间可以怎样互相影响,以及一个事务能看到其他事务的哪些修改。

假设你在查询账户余额,另一个事务正在扣款。此时有三个问题:

  1. 对方还没提交,我能看到它修改后的余额吗?
  2. 对方提交之后,我在同一个事务里再次查询,余额会变化吗?
  3. 如果我查询的是一批订单,对方新插入的订单会出现在第二次结果里吗?

这就是隔离级别要回答的问题。事务能保证一组操作一起提交或回滚,但多个事务之间的干扰还需要并发控制。

本篇先看并发问题,再比较四种隔离级别,最后讨论业务选择和常见误区。以下以 MySQL InnoDB 为主。

前置笔记:05.MySQL 事务。实现原理接着阅读 07.MySQL MVCC 和 08.MySQL 锁。

阅读提示:涉及 MVCC 和锁的内容会单独标注

本篇会提前用到 MVCC 的快照、Read View 和版本链,以及锁定读、共享锁、范围锁和死锁。相关位置会标注“涉及 MVCC”或“涉及锁”。第一次阅读时,先理解查询结果及并发操作的表现;快照与可见性原理在 07.MySQL MVCC 中展开,具体锁语法、类型与加锁范围在 08.MySQL 锁 中展开。

二、⚠️ 先认识三种读取异常

下面的事务 A、事务 B 表示两个独立连接中的事务。每个例子相互独立,重点看操作顺序以及事务是否已经提交。

2.1 脏读:读到了别人未提交的修改

账户余额原来是 1000 元:

顺序事务 A:扣款事务 B:查询
①将余额改成 900,尚未提交
②读到 900
③回滚,余额恢复为 1000

事务 B 读到的 900 最终没有生效。如果它据此拒绝付款或生成账单,就使用了错误的数据。

判断重点

看到了其他事务尚未提交的数据,就发生了脏读。对方即使后来提交,也不能改变读取发生时它尚未提交的事实。

2.2 不可重复读:同一事务里,同一行前后读到不同的值

账户余额仍然从 1000 元开始:

顺序事务 A:扣款事务 B:查询
①开始事务,第一次读取余额,得到 1000
②将余额改成 900,并提交
③在原事务内再次读取,得到 900

两次读到的都是已经提交的数据,因此没有脏读;但同一个事务内,同一账户的余额从 1000 变成了 900,出现了不可重复读。

判断重点

关注同一事务中重复读取同一行,内容是否保持一致。

2.3 幻读:同一事务里,相同条件查出的记录集合变了

订单表原来只有 1 条待支付订单:

顺序事务 A:新增订单事务 B:查询
①开始事务,查询待支付订单,得到 1 条
②插入另一条待支付订单,并提交
③在原事务内按相同条件查询,得到 2 条

查询条件始终是 status = 'PENDING',第二次却多出一条符合条件的记录,这就是幻读。其他事务删除记录或修改条件字段,也可能改变符合条件的记录集合。

判断重点

关注相同条件对应的记录集合是否变化。行数变化是常见表现,但即使总行数相同,集合中的成员也可能发生变化。

2.4 三种问题怎么区分

异常核心问题记忆方式
脏读读到了其他事务未提交的修改看了别人的草稿
不可重复读同一行前后读到的内容不同同一个账户的余额变了
幻读相同条件查出的记录集合不同待支付订单里多出一条记录

不可重复读和幻读的例子都要求两次读取发生在同一个事务中。如果用户刷新两次页面,每次查询都属于不同事务,看到新数据通常就是正常行为。

三、🧱 四种隔离级别分别保证什么

InnoDB 支持四种隔离级别,默认是 REPEATABLE READ(可重复读),实际配置可以修改。

先看 SQL 标准中常见的读异常对照,再单独理解 InnoDB 的实现:

隔离级别脏读不可重复读幻读
READ UNCOMMITTED(RU,读未提交)可能可能可能
READ COMMITTED(RC,读已提交)不允许可能可能
REPEATABLE READ(RR,可重复读)不允许不允许标准允许,InnoDB 需区分读取方式
SERIALIZABLE(可串行化)不允许不允许不允许

这张表的边界

这张表用于理解三种经典读异常,不能据此判断所有业务并发问题是否安全。例如,先查余额、在程序里计算、再写回固定值,仍需要单独设计并发保护,见第五章。

3.1 READ UNCOMMITTED:允许读取未提交的数据

账户余额原来是 1000 元,事务 B 使用 RU:

顺序事务 A:扣款事务 B:查询
①开始事务,将余额改成 900,尚未提交
②开始事务,普通查询可能读到 900
③回滚,余额恢复为 1000

事务 B 读到的 900 是事务 A 尚未提交的修改。A 随后回滚,B 已经看过的数字便失去了依据。

它允许脏读,也无法保证重复读取同一行或同一范围时结果稳定。学习时可以用它演示脏读,普通业务通常不采用。

3.2 READ COMMITTED:每次查询都以本次读取时的已提交数据为准

RC 避免读取其他事务未提交的修改,但允许后续查询看到其他事务新提交的数据。

涉及 MVCC:为什么每次查询可以看到新提交的数据

MVCC 即“多版本并发控制”,可以先理解为:数据库保留数据的多个版本,普通一致性读根据可见性规则选择能读取的版本。Read View 是判断哪些版本可见的依据。在 RC 下,每次普通一致性读都会建立新的 Read View,因此后一次查询可能看到前一次查询之后其他事务提交的修改。版本如何保存、如何判断可见,详见 07.MySQL MVCC。

顺序事务 A:扣款事务 B:查询
①开始事务,第一次普通查询余额,得到 1000
②将余额改成 900,并提交
③在原事务内再次普通查询,得到 900

这个结果符合 RC 的承诺:两次都读已提交数据,但两次查询的观察时间点可以不同。因此 RC 能防止脏读,仍可能发生不可重复读和幻读。

上面的余额例子展示了不可重复读。如果查询的是一批符合条件的记录,RC 也可能发生幻读。假设订单表原来只有 1 条待支付订单:

顺序事务 A:新增订单事务 B:查询
①开始事务,普通查询待支付订单,得到 1 条
②插入另一条待支付订单,并提交
③在原事务内按相同条件再次普通查询,得到 2 条

两次查询的条件都是 status = 'PENDING'。事务 A 提交后,事务 B 的第二次查询可以看到新订单,符合条件的记录集合从 1 条变成了 2 条,这就是幻读。两次都只读取已提交的数据,因此没有脏读。

3.3 REPEATABLE READ:同一事务中的普通查询复用稳定快照

涉及 MVCC:快照是什么

这里的“快照”指读取数据时使用的可见性视角,不是复制一份完整数据库。在 RR 下,同一事务的后续普通一致性读通常复用首次一致性读建立的 Read View,从数据版本中读取符合该视角的内容,所以其他事务提交后,本事务仍可能读到旧值。Read View、版本链以及本事务修改为何可见,详见 07.MySQL MVCC。

RR 下,第一次普通一致性读通常建立快照,后续普通一致性读复用它:

顺序事务 A:扣款事务 B:查询
①开始事务,第一次普通查询余额,得到 1000,并建立快照
②将余额改成 900,并提交
③在原事务内再次普通查询,仍然得到 1000
④提交事务
⑤开启新事务,普通查询余额,可以看到 900

RR 并非永远看不到新数据,而是让当前事务的普通一致性读保持稳定视角。需要读取新提交的数据时,可以结束原事务,在新事务中查询。

理解这条规则,要注意三个条件:

  • 同一个事务:不同事务不会因为都使用 RR 就自动共享同一快照。
  • 普通一致性读:SELECT ... FOR UPDATE 等锁定读不遵循同一套快照读取规则。
  • 事务自己的修改可见:如果本事务改了数据,后续查询可以看到自己的修改,不能把快照理解成完全冻结的数据库副本。

涉及锁: SELECT ... FOR UPDATE 是什么

它是在普通查询末尾加上 FOR UPDATE,表示读取时申请排他锁,为后续修改提供保护;这条查询本身不会修改数据。通常在显式事务中使用,锁在提交或回滚时释放。其他事务的冲突修改或加锁操作可能需要等待,普通快照查询通常仍可读取。这里先记住它属于“加锁的查询”,详细用法见 08.MySQL 锁。

快照通常在第一次普通一致性读时建立,单独执行 START TRANSACTION 不代表此时就已经固定了快照。版本链和快照可见性详见 07.MySQL MVCC。上述读取边界见 官方一致性读说明。

3.4 SERIALIZABLE:保证并发结果可以解释为某种串行顺序

可串行化要求:多个事务并发执行的结果,应当等价于它们按照某种先后顺序执行的结果。

它不意味着整个数据库同一时刻只能运行一个事务。事务仍可以并发执行,但冲突访问受到更严格的控制。

在 InnoDB 中,关闭自动提交时,普通 SELECT 会隐式转换为共享锁定读。例如,一个事务读取某个范围后,另一个事务尝试进行冲突修改,就可能需要等待。

这种保证通常带来更多锁等待,也可能出现死锁,需要应用处理重试。应当根据业务一致性要求和实际负载评估使用。

涉及锁:共享锁、锁等待与死锁

共享锁定读会对读取的数据加共享锁,其他事务的冲突修改可能需要等待;多个事务互相等待对方持有的锁,可能形成死锁。详细机制与处理方式见 08.MySQL 锁。

3.5 用一句话串起四种级别

其中 RC 与 RR 的普通一致性读涉及 MVCC,读取视角的实现原理见 07.MySQL MVCC。

RU:其他事务没提交的修改,也可能看到。
RC:每次普通查询,都看本次读取时已提交的数据。
RR:同一事务的普通查询,通常保持同一个快照视角。
可串行化:并发结果应等价于某种串行执行顺序。

四、🔍 InnoDB 的 RR 到底能不能防幻读

这是隔离级别最容易回答含糊的问题,必须说明使用了什么读取方式。

4.1 连续两次普通 SELECT:通过稳定快照保持结果集合

涉及 MVCC:新增订单为什么不可见

本节通过 MVCC 的快照可见性解释查询结果。即使其他事务已经插入并提交,新订单也不会自动进入当前事务原有的读取视角;后续普通查询仍按原 Read View 判断可见性。详细原理见 07.MySQL MVCC。

假设订单表原来只有 1 条待支付订单,事务 B 使用 RR,且没有修改相关数据。两次普通查询的条件都是 status = 'PENDING':

顺序事务 A:新增订单事务 B:普通查询
①开始事务,第一次普通查询待支付订单,得到 1 条,并建立快照
②开始事务,插入另一条待支付订单,并提交成功
③在原事务内按相同条件再次普通查询,仍然得到原来的 1 条
④提交事务
⑤开启新事务,再次普通查询,可以看到 2 条

看表时抓住一点:A 已经成功插入并提交,B 在原事务里仍然沿用旧快照,所以看不到新增的订单。

新订单在快照建立后提交,对这个快照不可见。这里保证的是查询视角稳定,事务 A 的插入仍然可以成功。

4.2 范围锁定读:通过锁限制其他事务插入

涉及锁:范围锁定读与锁类型

本节提前涉及 08.MySQL 锁 中的锁定读、记录锁、间隙锁与 next-key lock。先理解“查询时加锁,可以让其他事务的冲突操作等待”即可;具体加锁范围在锁的笔记中展开。下面的查询应放在显式事务中理解,锁通常保持到事务提交或回滚。

如果事务 B 使用范围锁定读:

SELECT * FROM orders WHERE status = 'PENDING' FOR UPDATE;

在 RR 下,InnoDB 通常会对实际扫描的索引范围使用记录锁与间隙锁(常见形式为 next-key lock)。其他事务向被锁定的间隙插入记录时,需要等待。

仍假设原来只有 1 条待支付订单,事务 B 使用 RR。以下以 status 上有索引、查询锁住相关索引范围,且 A 的新订单需要插入被锁定间隙为例;B 的两次查询都使用上面的 FOR UPDATE 写法:

顺序事务 A:新增订单事务 B:加锁查询
①开始事务,查询待支付订单并加锁,得到 1 条,锁住相关索引范围
②开始事务,尝试插入另一条待支付订单;插入位置受到 B 的锁保护,进入等待,插入尚未完成
③仍在等待,无法完成此次插入并提交在原事务内按相同条件再次加锁查询,仍然得到 1 条
④提交事务,释放锁
⑤等待结束,插入继续执行,完成后提交
⑥开启新事务,再次查询,可以看到 2 条

看表时抓住一点:B 持锁期间,A 的这次插入被阻塞;B 第二次查到 1 条,是因为新增订单还没能插进去。

这里保证的是对相应索引范围的并发修改进行限制。具体锁住什么范围取决于索引、查询条件和执行计划,详见 08.MySQL 锁 及 官方隔离级别说明。

4.3 两种保证不能混为一谈

本节同时涉及两部分知识:普通一致性读的快照与可见性属于 07.MySQL MVCC;锁定读与范围锁属于 08.MySQL 锁。

对比问题4.1:普通一致性读(涉及 MVCC)4.2:范围锁定读(涉及锁)
B 怎么查询?普通 SELECTSELECT ... FOR UPDATE
靠什么保持结果稳定?同一事务复用原快照锁保护实际扫描的相关索引范围
A 能插入这条新订单吗?可以插入并提交插入被锁定间隙时,需要等待
B 第二次为什么仍查到 1 条?新订单已提交,但对原快照不可见新订单的插入被阻塞,尚未完成
B 结束事务后呢?新事务可以建立新快照,看到已提交的新订单释放锁后,A 才能继续插入;A 提交后,新事务可以看到新订单

回答边界

可以说“InnoDB 的 RR 通过快照读和范围锁机制处理相应场景下的幻读”,但不能扩大为“事务里任何读写组合,查询结果都绝不会变化”。混用普通查询、锁定读和增删改,或者本事务修改了相关数据时,需要分别分析。

五、🛠️ 业务里怎么选,哪些问题还要单独处理

5.1 先判断:需要新的观察时间点,还是统一的统计口径

涉及 MVCC:报表为什么需要同一事务

本节的“统一数据视角”依赖 RR 事务内普通一致性读复用 Read View。不同事务不会自动共享同一 Read View,因此多条查询各自提交,不能保证使用同一快照。原理见 07.MySQL MVCC。

业务要求可以考虑使用条件
同一事务里的后续查询需要看到其他事务新提交的数据RC接受前后读取结果变化
对账、报表需要多次查询使用同一数据视角RR查询在同一事务中,主要使用普通一致性读
业务要求并发执行满足可串行化SERIALIZABLE评估锁等待、死锁重试和吞吐量
演示读取未提交数据RU只作为学习实验,普通业务通常不用

例如,一份报表依次统计订单数、支付金额和退款金额。如果要求这些查询基于同一个快照,需要把它们放在同一 RR 事务中执行;仅把数据库默认级别设为 RR,再执行三个各自自动提交的查询,不能保证它们共享快照。

用户刷新页面一般会发起新请求、开启新事务。即使使用 RR,也可以在下一次刷新时看到新提交的数据。因此,不能仅凭“页面要展示最新状态”,就断定必须选择 RC。

选择时先遵循业务一致性要求,再结合现有配置、查询方式和并发负载评估。RC 可能减少部分范围锁冲突,但不代表所有业务改成 RC 都更快。(涉及锁:范围锁、锁等待和死锁重试,详见 08.MySQL 锁。)

5.2 余额与库存:隔离级别不能代替业务并发控制

账户余额原来是 1000 元,事务 A 要扣 100 元,事务 B 要扣 200 元。两个事务都先普通查询余额,在程序里计算,再将算好的固定值写回:

顺序事务 A:扣款 100 元事务 B:扣款 200 元
①开始事务,普通查询余额,得到 1000
②开始事务,普通查询同一账户余额,也得到 1000
③在程序里计算:1000 - 100 = 900
④在程序里计算:1000 - 200 = 800
⑤将余额写成固定值 900,并提交
⑥将余额写成先前算好的固定值 800,并提交
结果对比余额原因
实际结果800 元B 将余额直接写成 800,覆盖了 A 的扣款效果
正确结果700 元两次扣款都应生效:1000 - 100 - 200 = 700

看表时抓住一点:B 写入的 800 是根据旧余额 1000 算出来的固定值,不是在数据库当前余额上再扣 200。

B 写回的固定值覆盖了 A 的扣款效果,这叫丢失更新。RC 或 RR 都不能自动识别应用写回的固定值已经过时。

常见处理方式:

方式怎么做如何避免上面的覆盖问题
条件原子更新执行 UPDATE account SET balance = balance - 100 WHERE id = 1 AND balance >= 100;,根据影响行数判断是否扣款成功让数据库在当前余额上直接扣款,避免写回程序根据旧余额算出的固定值
先锁再改(涉及锁,详见 08.MySQL 锁)在同一事务中使用 SELECT ... FOR UPDATE,读取并获得锁后再计算和修改其他事务的冲突修改需要等待,避免读取后、写入前被别人修改
版本号检查更新时同时检查旧版本号;不匹配则按业务要求重新读取并重试,或提示冲突发现读取后数据已被别人修改,就拒绝直接写回过时的计算结果

这些措施分别解决相应的并发修改问题;完整支付流程还需要事务、幂等与业务约束配合。

5.3 稳定快照也要控制事务时长

涉及 MVCC:旧版本为什么不能立即清理

旧数据版本可能仍被活跃事务的 Read View 使用,因此需要保留。长时间持有读取视角,可能延迟相关旧版本的清理。版本链、undo log 与旧版本清理的关系见 07.MySQL MVCC。

报表或导出事务持续太久,会长时间占用连接,并可能让旧版本无法及时清理。应控制事务时长,根据数据量选择合适的导出方案。

如果改为分批、分事务处理,就需要重新评估跨批次的一致性,不能同时假定每批独立提交又天然共享同一个 RR 快照。

六、🎤 高频面试题

6.1 MySQL 默认隔离级别是什么

InnoDB 默认是可重复读,也就是 REPEATABLE READ。实际环境可以修改,回答默认值时要明确存储引擎。

6.2 RC 和 RR 有什么区别

本题涉及 MVCC:两种级别建立、复用 Read View 的规则见 07.MySQL MVCC。

对普通一致性读,RC 的每次查询使用新的数据视角,能看到本次读取前其他事务已提交的修改;RR 的后续查询通常复用首次一致性读建立的快照。因此,两者都能避免脏读,RC 仍可能发生不可重复读,而 RR 能保持普通重复读取的稳定性。

6.3 不可重复读和幻读怎么区分

不可重复读关注同一行的内容是否变化;幻读关注相同条件对应的记录集合是否变化。两者都强调同一个事务内的重复读取。

6.4 InnoDB 的 RR 能防幻读吗

本题涉及 MVCC 和锁:稳定快照的可见性原理见 07.MySQL MVCC,范围锁定读与 next-key lock 的原理见 08.MySQL 锁。

要区分读取方式。连续普通一致性读通过同一个快照保持结果集合稳定;范围锁定读通过 next-key lock 等机制限制被锁定范围内的插入。混合读写和事务自身修改的情况需要单独分析,不能笼统说所有场景都不会变化。

6.5 隔离级别是不是越高越好

本题涉及锁:锁等待、死锁与并发保护方式见 08.MySQL 锁。

应当选择满足业务一致性要求的级别。更强的隔离可能增加等待、冲突与重试成本;余额、库存等业务还需要条件更新、锁或版本检查,不能只靠调整隔离级别。

七、📌 快速回顾与后续阅读

先识别问题:未提交数据?同一行变了?结果集合变了?
再理解规则:RU、RC、RR、SERIALIZABLE 分别提供什么保证?
最后落到业务:需要同一快照,还是后续查询看到新提交数据?
涉及写入:额外检查条件更新、锁、版本号和业务约束。

接下来阅读 07.MySQL MVCC,理解版本链与 Read View 如何实现可见性;再阅读 08.MySQL 锁,理解锁类型、范围及死锁。

八、🔗 官方资料