脏读是读取未提交数据导致业务决策错误,需读已提交级别防范;幻读是范围查询结果集行数变化,由插入/删除引发,rr级通过mvcc和间隙锁缓解但难彻底避免。

脏读和幻读是数据库事务并发执行时出现的两类典型一致性问题,本质都是因为多个事务交叉操作同一份数据,而隔离机制没到位。
脏读:读到了“还没定论”的数据
一个事务读取了另一个事务修改但尚未提交的数据。如果后者随后回滚,前者就读到了根本不存在的“假数据”。比如转账中A扣款但没提交,B查余额看到已扣,结果A因异常回滚,B却按错误余额做了后续操作。
- 关键特征:读取的是未提交的数据
- 后果:业务基于无效中间态做决策,容易引发连锁错误
- 解决方式:至少使用读已提交(Read Committed)隔离级别,数据库会跳过未提交版本
幻读:查询结果“多出来”或“少掉”了行
同一事务内,两次执行相同条件的范围查询(如SELECT * FROM orders WHERE user_id = 1),结果集行数不一致。这是因为其他事务在两次查询之间插入或删除了符合条件的新行。
在整本书中我们所涉及许多的Flex框架源码,但为了简洁,我们不总是显示所指的代码。当你阅读这本书时,要求你打开Flex Builder,或能够访问Flex3框架的源码,跟随着我们所讨论源码是怎么工作及为什么这样做。 如果你跟着阅读源码,请注意,我们经常跳过功能或者具体的代码,以便我们可以对应当前的主题。这样能防止我们远离当前的主题,主要是讲解代码的微妙之处。这并不是说那些代码的作用不重要,而是那些代码处理特别的案例,防止潜在的错误或在生命周期的后面来处理,只是我们当前没有讨论它。有需要的朋友可以下载看看
- 关键特征:不是单行值变了,而是符合条件的行集合发生了变化
- 常见场景:先查总数再插入,却发现插入失败(因另一事务已插入同条件记录);或分页查询时第二页出现重复/遗漏
- MySQL InnoDB 在可重复读(RR)下用 MVCC + 间隙锁(Gap Lock)缓解幻读,但严格意义的幻读仍可能发生在非唯一索引或无索引字段上
别混淆:幻读 vs 不可重复读
不可重复读聚焦于同一行数据内容被改(UPDATE/DELETE),幻读聚焦于符合条件的新行凭空出现或消失(INSERT/DELETE)。前者是“值变了”,后者是“行数变了”。
- 举个例子:查用户积分,第一次得100,第二次得200 → 不可重复读
- 查用户订单数,第一次3条,第二次4条 → 幻读
- 两者都可通过提升隔离级别抑制,但幻读更难彻底避免,尤其在高并发写入场景
怎么选隔离级别才稳妥
没有银弹,得看业务容忍度:
- 读已提交(RC):防脏读,适合大多数OLTP系统(如电商下单、账户查询),但无法防不可重复读和幻读
- 可重复读(RR):MySQL默认,防脏读+不可重复读,对多数幻读有防护(靠间隙锁),但极端情况仍需应用层配合(如SELECT FOR UPDATE)
- 串行化(Serializable):全防,但性能损耗大,仅用于极强一致性要求(如金融核心账务核对)
实际项目中,常搭配乐观锁、应用层重试、或关键路径显式加锁来补足隔离级别的盲区。









