MySQL 数据库 MVCC 与锁如何联手解决脏读、不可重复读、幻读

MySQL 数据库 MVCC 与锁如何联手解决脏读、不可重复读、幻读

本篇我用 「现象 → 根因 → MVCC 是否能解决 → 需要什么锁」 的方式,把

👉 脏读 / 不可重复读 / 幻读MVCC / 锁机制 一一对上号。

前置说明:

  1. 什么是MVCC?
    参考:《MySQL 数据库 MVCC 机制
  2. 什么是脏读、不可重复读、幻读,及隔离级别?
    参考:《MySQL 数据库 隔离级别 详解
  3. 什么是间隙锁?
    参考:《InnoDB Gap Lock 避坑指南:为什么查不到数据也会锁表?
  4. 什么是 Next-Key Lock ?
    参考:《3 分钟搞懂 Next-Key Lock:原理、触发场景

先给你结论

复制代码
并发现象        能否靠 MVCC 解决        还需不需要锁
---------------------------------------------------
脏读            ✅(最容易)              ❌
不可重复读      ✅(RC / RR)             ❌
幻读            ❌(仅 MVCC 不够)        ✅(Next-Key Lock)

📌 关键记忆点

MVCC 解决 "读旧数据" 的问题;
锁解决 "别人还能不能写" 的问题。


一、脏读(Dirty Read)

现象回顾

读到了 未提交 的数据


根因

  • 没有版本隔离
  • 直接读当前内存中的最新值

MVCC 怎么解决?

✅ 完全可以

  • Read View 只允许读:

    • 已提交事务
    • 自己的事务
text 复制代码
未提交事务 ∈ m_ids → 不可见

👉 自然不会脏读


需要锁吗?

不需要

  • 读历史版本即可
  • 写回滚也不影响读

对应隔离级别

隔离级别 是否可能脏读
RU
RC / RR ✅(MVCC)

二、不可重复读(Non-Repeatable Read)

现象回顾

同一行,两次读结果不同


根因

  • 两次 SELECT 使用了 不同的可见性规则
  • 世界观"变了"

MVCC 怎么解决?

✅ 可以

RC

  • 每条 SELECT 新 Read View
  • 所以 仍可能不可重复读

RR

  • 事务级 Read View
  • 多次 SELECT 看到的是同一个版本

👉 可重复读成立


需要锁吗?

不需要

  • 不要求别人不能改
  • 只是"我想看到一致视图"

对应隔离级别

隔离级别 不可重复读
RC
RR

三、幻读(Phantom Read)

现象回顾

同一条件,两次读到 不同行数


根因(重点)

  • 插入了新行
  • 新行在第一次 SELECT 时根本不存在
  • MVCC 只能决定"看哪个版本",无法阻止新行出现

MVCC 能解决吗?

❌ 只能解决一半

快照读(普通 SELECT)

  • 第二次 SELECT
  • 仍使用原 Read View
  • 看不到新插入行

👉 "看不到幻影"


当前读(FOR UPDATE / UPDATE)

  • 必须读最新数据
  • 不走 MVCC
  • 新行真实存在

👉 幻读仍可能发生


那怎么办?

✅ 必须靠锁

Next-Key Lock = 行锁 + 间隙锁

复制代码
锁住"未来可能插入的位置"
→ 插不进
→ 不会幻读

对应隔离级别

隔离级别 幻读
RC ❌(逻辑可能)
RR(InnoDB) ✅(锁 + MVCC)

四、把三者放到一张"机制对照表"

并发现象 发生在 MVCC 是否足够 锁是否必须
脏读 RU
不可重复读 RC RR 下 ✅
幻读 RC / 标准 RR

五、InnoDB 的终极设计思想

能用 MVCC 解决的,一律不加锁;
MVCC 解决不了的,才用锁;
锁只在"当前读"时才出现。


六、一个终极判断方法

读旧数据 → MVCC;
不让别人改 → 锁;
不让别人插 → Gap / Next-Key Lock。


七、总结

脏读和不可重复读是"看不看历史版本"的问题,
幻读是"新数据能不能出现"的问题,
前者靠 MVCC,后者必须靠锁。

若有转载🧪请标明出处:https://blog.csdn.net/CharlesYuangc/article/details/156310464

相关推荐
老华带你飞2 小时前
考试管理系统|基于java+ vue考试管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
哈里谢顿2 小时前
mysql索引影响查询速度的示例demo
mysql
WZTTMoon2 小时前
Spring Boot OAuth2 授权码模式开发实战
大数据·数据库·spring boot
AI题库2 小时前
PostgreSQL 18 从新手到大师:实战指南 - 1.1 PostgreSQL 18简介
数据库·postgresql
苏琢玉2 小时前
一次受限环境下的 MySQL 数据导出与“可交付化”实践
mysql·php
好记忆不如烂笔头abc2 小时前
Ubuntu 20.04.6上实现远程桌面连接
服务器·网络·数据库
今晚务必早点睡2 小时前
Redis——快速入门第七课:Redis 为什么这么快?
数据库·redis·缓存
EterNity_TiMe_3 小时前
从 0 到 1:Llama 3-8B 在昇腾 Atlas 800T 上的推理调优与算力榨干指南
数据库·llama·昇腾·atlas 800t·实战部署
talenteddriver3 小时前
mysql: MySQL中between子句和limit子句的区别
前端·javascript·数据库