脏读是指事务A读取到事务B修改但未提交的数据,若B回滚则A读取结果错误;仅在Read Uncommitted隔离级别下发生,MySQL默认Repeatable Read故不出现;应提升至Read Committed或更高隔离级别避免。

脏读,就是事务A读到了事务B改过但还没提交的数据。如果B后来回滚了,A读到的就完全是错的——这笔数据根本没真正发生过。
脏读发生的前提条件
它只会在最低的隔离级别下出现:Read Uncommitted(读未提交)。MySQL 默认是 Repeatable Read,所以默认不会脏读;但一旦显式设成 Read Uncommitted,就打开了这个风险口。
- 事务B执行 UPDATE 或 DELETE,但没 COMMIT
- 事务A此时执行 SELECT,且隔离级别允许读未提交
- A拿到的是B中途写入的中间状态,不是数据库最终持久化的值
一个真实可复现的例子
假设账户表有一条记录:id=1, balance=100。
- 事务B开始:
BEGIN; UPDATE account SET balance = 80 WHERE id = 1;(不提交) - 事务A开始(隔离级别为 READ UNCOMMITTED):
SELECT balance FROM account WHERE id = 1;→ 返回 80 - 事务B执行
ROLLBACK;→ 余额实际仍是 100 - 但事务A已经按 80 做了后续计算(比如再扣10),结果算出 70,而真实余额是 100
为什么脏读危险?
它破坏的是“读一致性”底线:读操作不该依赖随时可能消失的临时状态。
- 业务逻辑出错:比如风控系统基于脏余额放行交易,实际资金不足
- 报表失真:统计任务读到未提交的订单量,导出错误日报
- 连锁错误:下游服务用脏数据生成通知、触发回调,无法撤回
怎么避免脏读
最直接有效的方式是提升事务隔离级别:
- 用 READ COMMITTED:确保只读已提交的数据(InnoDB 默认支持,开销小)
- 用 REPEATABLE READ(MySQL InnoDB 默认):进一步保证同一事务内多次读一致
- 不推荐靠
SELECT ... FOR UPDATE或锁来防脏读——那是治标,改隔离级别才是治本










