并发事务同时读写时会遇到各种一致性问题,隔离级别就是「在并发与一致性之间选一个平衡点」。理解它,才能正确设计事务和复用数据库的默认行为。
一、并发事务的三种现象
| 现象 | 含义 |
|---|---|
| 脏读 | 读到其他事务未提交的数据 |
| 不可重复读 | 同一事务内两次读同一行,结果不同 |
| 幻读 | 同一事务内两次范围查询,结果集行数不同 |
由弱到强,隔离级别就是对这三种现象的「逐步收口」。
二、四种隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | 可能 | 可能 | 可能 |
| READ COMMITTED | 避免 | 可能 | 可能 |
| REPEATABLE READ | 避免 | 避免 | 可能 |
| SERIALIZABLE | 避免 | 避免 | 避免 |
三、常见数据库的默认值与实现
MySQL(InnoDB)默认是 REPEATABLE READ,但通过 MVCC(多版本并发控制)+ 间隙锁,实际上也避免了幻读。它的实现方式是:
- MVCC 让普通读(快照读)不加锁,靠版本号实现一致性快照。
- 对范围查询加间隙锁(gap lock),阻止其他事务插入新行,从而避免幻读。
PostgreSQL 默认是 READ COMMITTED,同样用 MVCC 实现,但普通读不产生间隙锁,在 REPEATABLE READ 下也主要靠快照对付幻读。
Oracle 默认是 READ COMMITTED,且只支持 READ COMMITTED 和 SERIALIZABLE 两种。
四、实际开发怎么选
- 默认用数据库默认值即可,绝大多数场景 READ COMMITTED(PG/Oracle)或 REPEATABLE READ(MySQL)都够用。
- 需要强一致时用 SERIALIZABLE,但对并发性能影响大,要谨慎评估。
- 别用 READ UNCOMMITTED,脏读带来的数据错误很难排查。
- 事务要短:隔离级别锁定的资源随事务存活时间越长,冲突概率越高,尽量把事务控制在最小范围。
五、一个容易混淆的点
「不可重复读」和「幻读」的区别在于:不可重复读针对同一行的数据变化,幻读针对结果集行数的变化。MySQL 的 REPEATABLE READ 通过 MVCC 解决了前者,通过间隙锁解决了后者,所以 MySQL 的 RR 实际等价于别的数据库的 SERIALIZABLE 在幻读上的表现。
小结
隔离级别是「并发与一致性」的权衡。理解脏读、不可重复读、幻读三种现象,再对照各数据库的默认值和实现差异,就能为业务选择合适的事务隔离级别,而不是盲目提升或降低。