HelloCoder HelloCoder
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
  • 《k8s学习心得》
随笔
关于作者
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
  • 《k8s学习心得》
随笔
关于作者
  • 《LearnJavaToFindAJob》

    • 导读

    • 【初级】6~12k档

    • 【中级】12k-26k档

      • JVM进阶

      • Java进阶

      • MySQL

        • Innodb和MyISAM索引的区别
        • MySQL-like是否可以使用索引
        • MySQL一些索引失效的场景和原理
        • MySQL大表索引重建
        • MySQL如何行转列?
        • MySQL死锁的场景
        • MySQL的架构和执行流程
        • MySQL的缓存
        • MySQL的自增ID用完了会怎样?
        • MySQL索引的分类、何时使用、何时不使用、何时失效?
        • MySQL联合索引在B+数的存储结构和最左匹配原则原理
        • MySQL连表优化
        • MySQL连表查询的原理
        • MySQL那种事务隔离级别性能高
        • Mysql的索引和主键的区别
        • binlog、redolog、undolog的区别和作用
        • 什么是前缀索引,什么情况才使用?
        • 可重复读是否能解决幻读?
        • 我以为我对Mysql事务很熟,直到我遇到了阿里面试官
        • 聊聊MySQL索引的分类和结构吧
        • 脏读、幻读
      • 中间件

      • 算法

      • 高阶

    • 【高级】26k+档

    • 大厂面试题

    • 求职建议

    • 面经

  • LearnJavaToFindAJob
  • 【中级】12k-26k档
  • MySQL
#脏读 #幻读
HaC
2026-06-25
目录

脏读、幻读

# 一、四个隔离级别是什么?

隔离级别 英文名 脏读 不可重复读 幻读
读未提交 READ UNCOMMITTED ✅ 可能 ✅ 可能 ✅ 可能
读已提交 READ COMMITTED ❌ 不会 ✅ 可能 ✅ 可能
可重复读 REPEATABLE READ ❌ 不会 ❌ 不会 ✅ 可能(MySQL InnoDB 通过 MVCC 避免)
串行化 SERIALIZABLE ❌ 不会 ❌ 不会 ❌ 不会

隔离级别越严格,性能越差,数据一致性越好。

# 二、场景

# 1️⃣ 脏读(Dirty Read):读到了别人还没提交的数据

场景: 事务 A 修改了余额,但还没提交;事务 B 读到了这个未提交的数据。

时间 事务 A 事务 B
T1 BEGIN;
T2 UPDATE account SET balance=800 WHERE id=1;(还没提交) 读未提交
T3 BEGIN;
T4 SELECT balance FROM account WHERE id=1; → 读到了 800
T5 ROLLBACK;(回滚了,余额变回 1000)
T6 事务 B 一直以为余额是 800,实际上错了

结论: 事务 B 读到了一条根本不存在的数据(回滚后就没了),这就是脏读。

读未提交允许脏读,读已提交及以上不允许。


# 2️⃣不可重复读(Non-Repeatable Read):两次读同一条数据,结果不一样

场景: 事务 A 修改并提交了数据;事务 B 在同一事务中两次查询,结果不同。

时间 事务 A 事务 B
T1 BEGIN;
T2 SELECT balance FROM account WHERE id=1; → 1000
T3 BEGIN;
T4 UPDATE account SET balance=800 WHERE id=1; COMMIT; 读已提交
T5 SELECT balance FROM account WHERE id=1; → 800
T6 COMMIT;

结论: 同一事务内,查询同一条数据,前后结果不一致(1000 → 800),这就是不可重复读。

读已提交允许不可重复读,可重复读及以上不允许。


# 3️⃣ 幻读(Phantom Read):两次查询的行数不一样

场景: 事务 A 插入了一条新数据并提交;事务 B 在同一个事务中两次查询,行数不同。

时间 事务 A 事务 B
T1 BEGIN;
T2 SELECT * FROM account WHERE name LIKE '张%';
1 行(张三)
T3 BEGIN;
T4 INSERT INTO account VALUES (2,'张四',500); COMMIT;
T5 SELECT * FROM account WHERE name LIKE '张%';
2 行(张三、张四)
T6 COMMIT;

结论: 同一事务内,同一个查询条件,返回的记录数量变了,这就是幻读。

可重复读在 MySQL InnoDB 中通过 MVCC(多版本并发控制)或间隙锁(Gap Lock)来避免幻读,但其他数据库(如 PostgreSQL)的默认隔离级别可能需要更高设置。


# 三、不同隔离级别能解决什么问题?

隔离级别 能解决什么问题? 典型使用场景
读未提交 什么都不解决,性能最高 几乎不用,数据一致性太差
读已提交 解决脏读 大多数 OLTP 系统(如电商订单),追求性能且可接受短暂不一致
可重复读 解决脏读 + 不可重复读 MySQL 默认级别,适合报表类业务,对数据一致性要求较高的场景
串行化 解决所有问题(脏读、不可重复读、幻读) 极少数对一致性要求极高且并发低的场景(如银行核心账务)

# 四、快速记忆口诀

读未提交,什么都读(脏、幻、不可重复全都有) 读已提交,只能读到提交的(脏读没了,但幻读和不可重复读还在) 可重复读,读到的始终一样(脏读和不可重复读没了,MVCC 下幻读也没了) 串行化,统统排队(所有问题都解决,但性能最差)


# 五、一句话总结

  • 脏读 = 读到别人没提交的垃圾数据
  • 不可重复读 = 读同一行数据,前后值不一样
  • 幻读 = 查询同一张表,前后行数不一样

隔离级别从低到高,一步步堵住这些漏洞。

#脏读#幻读
上次更新: 2026-06-25 17:18:05
最近更新
01
MySQL支持的锁有哪些
06-25
02
HTTP 是不保存状态的协议, 如何保存用户状态
06-25
03
WebSocket、短轮询、长轮询的区别
06-25
更多文章>
Theme by Vdoing | Copyright © 2020-2026 HaC
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式