READ UNCOMMITTED 允许脏读是 MySQL 的明确设计,非 bug;它不加读锁、不维护一致性视图,适用于监控、统计等可容忍不一致的场景,但需避免全局设置或事务中修改。

READ UNCOMMITTED 确实允许脏读,不是 bug 是设计
MySQL 8.0+ 的 READ UNCOMMITTED 隔离级别下,事务能读到其他未提交事务的修改——这是标准行为,不是配置错误或引擎缺陷。InnoDB 完全支持该级别,且不加任何行级读锁(SELECT 不生成 next-key lock 或 gap lock),连 consistent read 版本也不维护。
常见误判现象:
- 执行
SELECT瞬间看到另一事务UPDATE但尚未COMMIT的值 - 随后对方
ROLLBACK,你查到的数据就“凭空消失”或变成旧值 -
SHOW ENGINE INNODB STATUS中看不到对应读锁等待,容易误以为“没并发问题”
哪些场景真会临时用 READ UNCOMMITTED
它极少用于业务主流程,但某些诊断、监控或离线分析场景下,牺牲一致性换响应速度是可接受的:
- 实时大表统计行数(
SELECT COUNT(*) FROM huge_log_table),避免被长事务阻塞 - 运维脚本快速采样异常连接状态(如从
information_schema.PROCESSLIST查活跃 SQL) - ETL 导入前做粗略数据存在性探查,不依赖精确结果
- 开发环境模拟高并发读压力时,绕过锁竞争观察吞吐瓶颈
注意:READ UNCOMMITTED 对 UPDATE/DELETE 仍加写锁,只影响 SELECT 行为。
SET TRANSACTION ISOLATION LEVEL 临时生效,别改全局
临时切换隔离级别必须用会话级命令,且需在事务开始前设置:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; START TRANSACTION; SELECT * FROM audit_log WHERE status = 'pending' LIMIT 10;
以下操作是危险的:
- 执行
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED:影响所有新连接,极易引发上游应用脏读故障 - 在已开启事务后调用
SET TRANSACTION...:MySQL 报错ERROR 1568 (25001): Transaction characteristics can't be changed while a transaction is in progress - 用
SELECT ... FOR UPDATE搭配READ UNCOMMITTED:后者被忽略,InnoDB 仍按当前事务隔离级别加锁
比 READ UNCOMMITTED 更安全的替代方案
多数所谓“要快”的需求,其实不需要脏读,而是想绕过锁或 MVCC 开销:
- 查元数据或状态表(如
performance_schema):默认无锁,无需降级隔离级别 - 大表
COUNT(*):用近似值SELECT table_rows FROM information_schema.TABLES(MyISAM 精确,InnoDB 是估算) - 需要最终一致但不强求实时:改用
READ COMMITTED+ 应用层重试逻辑 - 监控类查询:加
/*+ MAX_EXECUTION_TIME(1000) */提示避免长阻塞,比降级更可控
真正要用 READ UNCOMMITTED 时,务必确保上层业务能容忍“读到回滚数据”这一确定性风险——这不是概率问题,是必然可能发生的行为。










