脏读是读到未提交的假数据,不可重复读是同一行值被已提交更新改变,幻读是范围查询结果集行数因插入/删除而变化;三者分别对应READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ隔离级别下典型并发异常。

MySQL中这三类读并发问题,本质是事务间“读”与“写”交错时,隔离机制没兜住导致的语义错乱。不是概念背诵题,而是要能一眼识别现场现象、对应到具体异常类型、再决定要不要调隔离级别或加锁。
脏读:读到了别人还没拍板的数据
典型现象是SELECT返回了另一事务UPDATE过但尚未COMMIT的值,而那个事务随后ROLLBACK了——你手里的数据从一开始就是假的。
- 发生条件:隔离级别为
READ UNCOMMITTED,或显式禁用一致性读(如SELECT ... FOR UPDATE在低级别下可能触发) - 关键信号:错误日志里没报错,但业务逻辑明显基于“不存在的中间态”做了判断(比如库存显示负数后又恢复)
- MySQL默认不出现:因为默认是
REPEATABLE READ,MVCC直接屏蔽未提交版本
不可重复读:同一行,两次查,值变了
事务A第一次SELECT id=1得balance=100,事务B接着UPDATE id=1 SET balance=200并COMMIT,事务A再查就变成200。这不是幻觉,是真实更新被你读到了。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 和脏读区别:这里读到的是已提交数据,所以更隐蔽;但破坏的是“单行值稳定性”
- 常见于无主键/无索引字段的
UPDATE,InnoDB会升级为表锁,放大影响范围 -
READ COMMITTED能防脏读但防不住它;REPEATABLE READ靠事务首次查询生成的ReadView快照解决
幻读:同一条件,两次查,行数对不上
事务A执行SELECT * FROM orders WHERE status='pending'得5条,事务B插入1条同状态记录并提交,事务A再执行同样语句得6条。注意:不是某行内容变,是“多出来一行”。
- 容易混淆点:如果事务B是
UPDATE已有行的status字段,那属于不可重复读;只有INSERT或DELETE才触发幻读 - MySQL的
REPEATABLE READ实际能防大部分幻读:通过Next-Key Lock(间隙锁+记录锁)堵住插入点 - 但纯MVCC快照读(普通
SELECT)不锁间隙,所以严格来说幻读仍可能发生;真正防死得用SELECT ... FOR UPDATE或升到SERIALIZABLE
真正难处理的从来不是定义,而是线上查到两版结果不一致时,得立刻判断:是某行值被改了(不可重复读),还是凭空多/少了一行(幻读),抑或压根读了回滚前的垃圾(脏读)——这决定了你该看SHOW ENGINE INNODB STATUS里的锁信息,还是直接调隔离级别,或者补WHERE条件上的索引。










