一句话定义:事务隔离级别(Isolation Level)是数据库给“多个事务同时读写同一份数据”定的规矩,规定你什么时候能看到别人还没收尾的改动。
先认识三种毛病
假设你和同事同时在改同一张账单表。
- 脏读(Dirty Read):同事把余额从 100 改成 200,还没提交,你就读到了 200;他随后回滚,你手里这份数据从未存在过。
- 不可重复读(Non-Repeatable Read):你在自己的事务里读余额是 100,同事改了并提交,你在同一个事务里再读变成 200。同一行,两次结果不一样。
- 幻读(Phantom Read):你查“余额大于 50 的记录”得到 3 条,同事插入一条余额 80 并提交,你在同一个事务里再查变成 4 条。多出来的那行像幻觉。
四个档位
| 级别 | 脏读 | 不可重复读 | 幻读 | 快照何时确定 |
|---|---|---|---|---|
| 读未提交 Read Uncommitted | 会 | 会 | 会 | 不取快照 |
| 读已提交 Read Committed | 不会 | 会 | 会 | 每条语句开始时 |
| 可重复读 Repeatable Read | 不会 | 不会 | 标准上不保证 | 事务开始时 |
| 串行化 Serializable | 不会 | 不会 | 不会 | 靠排队,不靠快照 |
差别就在最后一列的时间点。读已提交像“每次刷新都看最新版”;可重复读像“进门时拍一张照,之后整个事务只看这张照片”。所以可重复读能挡住不可重复读——同事提交之后,你翻的仍然是旧照片。
幻读更麻烦的地方在于:快照锁得住“已经存在的行”,锁不住“新长出来的行”。标准里的可重复读只承诺行级结果一致,范围查询并不保证。有些数据库实现得更严,会用间隙锁一类的机制把范围也挡住,让幻读基本不出现;你的数据库到底属于哪种,以官方文档为准。
和相邻概念的区别
隔离级别只回答“并发事务之间看不看得见”,不回答“事务中途失败能不能回滚”——那是原子性(Atomicity)的活。它也不承诺性能:级别越高,等待和重试越多,并发能力越低,这是一笔明确的取舍。
对从业者的实际意义
写扣款、扣库存、发积分这类“先读、再判断、再写”的逻辑时,别指望调高隔离级别就一劳永逸。快照读看到的可能是历史版本,两个人各自基于同一份旧数据扣一次,账照样算错。更稳的做法是显式加锁、唯一约束,或者带版本号的乐观锁,把冲突变成一次明确的失败和重试。
对普通人的体感是:同一条记录刷新两次数字不一样,或者页面显示有货、点进去下单却失败——多半就是一个还活在快照里,一个已经走到了现实前面。
