当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL 事务隔离解释一致性读与当前读差异的实现方法

MySQL 事务隔离解释一致性读与当前读差异的实现方法

来源:17golang原创 2026-09-19 23:00:48 0浏览 收藏

我排查过一类很容易误判的库存问题:事务里的普通 SELECT 明明看不到刚提交的数据,紧接着 UPDATE 却能命中它。根因通常不是 MySQL 随机返回结果,而是两条语句使用了不同的读方式。InnoDB 的普通查询是一致性读,依赖 read view;UPDATEDELETE 和带 FOR SHAREFOR UPDATE 的查询属于当前读或锁定读,要面对最新可用版本。

只想稳定地读一份事务快照,用普通 SELECT;读完马上要改,或必须判断最新库存,用 FOR UPDATE;只保护关联行不被修改,用 FOR SHARE。不要在 REPEATABLE READ 事务里把快照读和当前读的结果当成同一张表。
要点速览
  • InnoDB 默认隔离级别是 REPEATABLE READ,同一事务的普通 SELECT 通常复用首次一致性读的快照。
  • READ COMMITTED 会让每次一致性读获得新快照,但不会把普通 SELECT 自动变成加锁读取。
  • FOR UPDATE 面向最新可用行并加排他锁,锁在提交或回滚后释放,适合读取后修改。

普通 SELECT 为什么会停留在旧快照

一致性读的目标是让查询看到一个稳定的数据库时间点。REPEATABLE READ 下,事务第一次执行普通 SELECT 时建立 read view,之后同一事务的普通查询继续按这个视图判断哪些版本可见。因此,另一个事务后来提交的插入、更新或删除,不会自动改变这份快照。

这个规则只约束一致性读,不代表事务中的所有语句都使用同一视图。尤其是写语句需要定位可修改的真实行,不能拿过期版本直接加锁。排查时先记下每条语句的类型、首次普通 SELECT 的位置和两个事务的 COMMIT 顺序。

MySQL InnoDB REPEATABLE READ 中事务、read view 与可见行版本的关系说明图
图1:InnoDB 一致性读的 read view 关系说明图,不是运行截图。

隔离级别怎样改变一致性读的时间点

下面的示例只用于构造两个会话的观察场景。注释保留在 SQL 内,方便把事务边界和检查动作对应起来:

-- 会话 A:先建立普通 SELECT 的观察时间点
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT id, stock FROM inventory WHERE id = 7; -- 首次一致性读建立 read view

-- 会话 B:另一个事务提交库存变化
START TRANSACTION;
UPDATE inventory SET stock = stock - 1 WHERE id = 7; -- 写入新版本并持有行锁
COMMIT; -- 提交后,新版本对后续合适的读可见

-- 会话 A:普通 SELECT 仍按原快照读取
SELECT id, stock FROM inventory WHERE id = 7; -- REPEATABLE READ 下可能仍是旧值
COMMIT; -- 结束事务,下一次事务才会建立新的观察点

-- 需要每次普通查询都刷新视图时,在新事务开始前选择 READ COMMITTED
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

REPEATABLE READ 适合报表式的事务内稳定读取;READ COMMITTED 则让每次一致性读使用新快照,适合更关注最新已提交状态的场景。改隔离级别前先确认应用的 binlog、锁等待和可重复读取要求,不能只为“看到新值”就全局调整。

需要最新值时怎样切换到当前读

如果业务动作是“读取库存后扣减”“检查父记录后插入子记录”或“读取计数器后递增”,普通 SELECT 与后续写入之间存在竞态。此时应该在同一事务内使用锁定读:

-- 读取库存并锁住当前行,随后在同一事务中完成扣减
START TRANSACTION;
SELECT stock FROM inventory WHERE id = 7 FOR UPDATE; -- 当前读:等待并读取最新可用版本
UPDATE inventory SET stock = stock - 1 WHERE id = 7; -- 依据已锁定的行执行修改
COMMIT; -- 提交修改并释放 FOR UPDATE 持有的锁

-- 只需保护关联记录时使用共享锁,允许其他事务继续读取
START TRANSACTION;
SELECT id FROM parent WHERE id = 9 FOR SHARE; -- 防止父记录在本事务完成前被修改或删除
INSERT INTO child(parent_id, value) VALUES (9, 'demo'); -- 继续写入关联数据
COMMIT; -- 提交后释放共享锁

FOR UPDATE 是排他锁语义,FOR SHARE 是共享锁语义;它们可能等待其他事务结束。锁定读必须放在显式事务中,且锁的范围仍受索引条件、范围扫描和隔离级别影响,不能把一条 SQL 简化成“永远只锁一行”。

MySQL 普通 SELECT、FOR SHARE、FOR UPDATE 与 UPDATE 的读版本和锁关系说明图
图2:一致性读、当前读与锁定读的选择关系说明图,不是运行截图。

三类现象的排查清单

现象先检查处理方向
SELECT 看不到,UPDATE 却命中是否在 REPEATABLE READ 的旧 read view 中区分展示查询与写前校验,必要时使用锁定读
同一事务的普通查询不刷新首次 SELECT、隔离级别和 COMMIT 边界提交后重开事务,或评估 READ COMMITTED
FOR UPDATE 长时间等待阻塞事务、索引条件和未提交事务缩短事务,补合适索引,按业务决定 NOWAIT/SKIP LOCKED

我的经验是先把语句分成“看快照”“看最新值”“读取并准备修改”三组,再看事务边界;直接把所有查询改成 FOR UPDATE,往往只会把读请求变成锁竞争。

相关问题

普通 SELECT 会不会加行锁?

在 InnoDB 的一致性读模式下,普通 SELECT 不为访问的表设置锁,其他事务可以同时修改。它的保护重点是可见性,不是阻止并发写入。

FOR SHARE 和 FOR UPDATE 怎么选?

后续只需要保证关联行在事务完成前不被修改,可用 FOR SHARE;读取后要更新行或递增计数器,应使用 FOR UPDATE。

READ COMMITTED 能解决所有旧数据问题吗?

不能。它只改变一致性读建立快照的频率;需要读取后安全修改时,仍应使用合适的锁定读并缩短事务范围。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go os/exec读取子进程标准输出的资源管理Go os/exec读取子进程标准输出的资源管理
上一篇
Go os/exec读取子进程标准输出的资源管理
Go encoding/xml用 Token 读取混合内容的解析方法
下一篇
Go encoding/xml用 Token 读取混合内容的解析方法
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    121次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    196次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    139次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    114次使用
  • CMMLU中文大模型评估基准:功能、使用教程与应用场景解析
    CMMLU
    深入了解CMMLU中文评估基准,涵盖67个学科主题,提供数据集下载、Zero-shot/Five-shot评估方法及排行榜,助力优化中文语言模型性能。
    96次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码