一、MySQL 的事务隔离级别(SQL 标准定义的四种)
- 读未提交(Read Uncommitted)
- 特点:事务中的修改即使还没有提交,也能被其他事务看到。
- 问题:可能出现脏读 、不可重复读 、幻读。
- 读已提交(Read Committed)
- 特点:事务只能读取到已经提交的数据。
- 问题:可以避免脏读,但仍可能出现不可重复读 、幻读。
- 典型数据库:Oracle 默认就是这个隔离级别。
- 可重复读(Repeatable Read)
- 特点:在同一个事务中,多次读取同一条记录的结果是一样的(保证可重复读)。
- 问题:可以避免脏读和不可重复读,但仍可能出现幻读。
- MySQL InnoDB 默认隔离级别 ,它在 MVCC + Next-Key Lock 的机制下,实际上也能避免幻读。
- 串行化(Serializable)
- 特点:最高级别,所有事务串行执行,读写都加锁。
- 问题:避免了脏读、不可重复读、幻读,但性能最差。
MySQL 事务隔离级别对比表
隔离级别 | 能否避免脏读 | 能否避免不可重复读 | 能否避免幻读 | 说明 |
---|---|---|---|---|
读未提交 (Read Uncommitted) | ❌ | ❌ | ❌ | 任何事务都能读到其他事务未提交的数据,问题最多,几乎不用 |
读已提交 (Read Committed) | ✅ | ❌ | ❌ | 只能读已提交的数据,避免了脏读,但可能出现不可重复读、幻读。Oracle 默认 |
可重复读 (Repeatable Read) | ✅ | ✅ | 标准SQL: ❌ InnoDB: ✅ | 保证同一事务内多次读到的数据一致;InnoDB 通过 MVCC + Next-Key Lock 甚至可以避免幻读。MySQL 默认 |
串行化 (Serializable) | ✅ | ✅ | ✅ | 所有事务串行执行,读写都加锁,安全性最高但性能最差 |
记忆口诀
- 读未提交 → 啥问题都有
- 读已提交 → 解决脏读
- 可重复读 → 再解决不可重复读(MySQL 下还能解决幻读)
- 串行化 → 全解决,但性能最差
二、MySQL 默认隔离级别
- MySQL(InnoDB 存储引擎)默认的事务隔离级别是:Repeatable Read(可重复读)
为什么选择它?
- 性能与一致性的平衡 :
- 比串行化要高效得多(不会强制事务串行执行)。
- 比读已提交更安全,避免了不可重复读。
- 结合 MVCC(多版本并发控制) 和 Next-Key Lock(间隙锁) ,在 InnoDB 中,实际上幻读也可以避免,因此 InnoDB 的可重复读比 SQL 标准更强。
三、常见并发问题的定义
- 脏读(Dirty Read)
- 一个事务读到了另一个事务未提交的数据。
- 如果另一个事务回滚,那么第一个事务读到的数据就是"脏"的。
- 不可重复读(Non-Repeatable Read)
- 在同一事务中,两次读取同一条记录,结果不一致(因为另一事务修改并提交了)。
- 关注的是 同一行记录被修改。
- 幻读(Phantom Read)
- 在同一事务中,两次执行相同的查询,第二次却出现了"多出来的行"或"少了一些行"。
- 关注的是 记录数量发生变化(另一事务插入/删除了满足条件的新行)。
📌 总结一下记忆口诀:
- 脏读:读到"别人还没提交"的数据。
- 不可重复读:同一行,两次结果不一样。
- 幻读:同一个条件,两次查结果数量不一样。