文章目录
-
- [《MySQL 四种隔离级别:从脏读到幻读的全过程》](#《MySQL 四种隔离级别:从脏读到幻读的全过程》)
-
- 一、前言:为什么要有隔离级别
- 二、核心概念回顾
- 三、四种隔离级别概览表
- 四、通过时间线理解四种隔离级别
-
- [(1)READ UNCOMMITTED(读未提交)](#(1)READ UNCOMMITTED(读未提交))
- [(2)READ COMMITTED(读已提交)](#(2)READ COMMITTED(读已提交))
- [(3)REPEATABLE READ(可重复读)](#(3)REPEATABLE READ(可重复读))
- (4)SERIALIZABLE(可串行化)
- [五、MySQL 各级别的底层实现](#五、MySQL 各级别的底层实现)
- 六、面试高频问题与答题模板
- 七、总结
《MySQL 四种隔离级别:从脏读到幻读的全过程》
一、前言:为什么要有隔离级别
大家好,我是程序员卷卷狗。
在数据库中,同时运行多个事务是常态。
如果事务之间完全不隔离,
就会出现 脏读、不可重复读、幻读 等问题。
不同的业务场景,对"性能与一致性"的要求不同。
于是 SQL 标准定义了四种事务隔离级别,用来平衡两者。
一句话概括:
隔离级别 = 性能与一致性的权衡。
二、核心概念回顾
| 概念 | 含义 | 示例 |
|---|---|---|
| 脏读 | 读到其他事务未提交的数据 | A 读到 B 尚未提交的修改 |
| 不可重复读 | 同一事务多次读取结果不同 | A 两次读同一行,B 中途修改 |
| 幻读 | 同一查询多次执行结果行数不同 | A 查询符合条件行数,B 中途插入新行 |
三、四种隔离级别概览表
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 实现机制 |
|---|---|---|---|---|
| READ UNCOMMITTED | ✅ | ✅ | ✅ | 无隔离,读未提交 |
| READ COMMITTED | ❌ | ✅ | ✅ | 每次读生成新 ReadView |
| REPEATABLE READ(默认) | ❌ | ❌ | ✅(部分避免) | 固定 ReadView + 间隙锁 |
| SERIALIZABLE | ❌ | ❌ | ❌ | 全表加锁,串行执行 |
✅ 表示可能发生 该问题,❌ 表示不会发生。
四、通过时间线理解四种隔离级别
假设有两笔事务:
T1(读操作) T2(写操作)
我们来看它们交叉执行的效果。
(1)READ UNCOMMITTED(读未提交)
| 时间 | 事务 T1 | 事务 T2 |
|---|---|---|
| t1 | 查询余额 → 得到 100 | |
| t2 | UPDATE balance=0;(未提交) | |
| t3 | T1 再次查询余额 → 得到 0 | ❌ 脏读 |
| t4 | T2 回滚 |
T1 读到了未提交的数据。
特点:几乎无隔离,性能最高,一致性最差。
一般只用于日志类或临时统计业务。
(2)READ COMMITTED(读已提交)
| 时间 | 事务 T1 | 事务 T2 |
|---|---|---|
| t1 | 查询余额 → 得到 100 | |
| t2 | UPDATE balance=0; COMMIT; | |
| t3 | T1 再次查询余额 → 得到 0 | ❌ 不可重复读 |
T1 在一个事务中读到了两次不同的结果。
原因:每次 SELECT 都生成新的 ReadView。
Oracle 默认就是 READ COMMITTED,适用于"读实时性较高"的系统。
(3)REPEATABLE READ(可重复读)
| 时间 | 事务 T1 | 事务 T2 |
|---|---|---|
| t1 | 查询余额 → 得到 100 | |
| t2 | UPDATE balance=0; COMMIT; | |
| t3 | T1 再次查询余额 → 仍然得到 100 | ✅ 可重复读 |
T1 在同一事务内看到的数据一致,
因为它的 ReadView 只在第一次查询时生成。
但如果 T2 插入一条新数据:
sql
INSERT INTO account (id,balance) VALUES (3,200);
T1 再执行范围查询:
sql
SELECT * FROM account WHERE balance > 100;
→ 可能会看到新的行。
这就是"幻读"。
InnoDB 通过 间隙锁(Gap Lock) + MVCC 共同避免幻读。
(4)SERIALIZABLE(可串行化)
在该级别下,所有读写都被加锁,事务串行执行。
即便是读操作,也会被锁定。
T1: SELECT * FROM account; -- 加锁
T2: INSERT INTO account ... -- 阻塞等待
保证绝对一致性,但性能最差。
一般仅用于金融或账务系统。
五、MySQL 各级别的底层实现
| 隔离级别 | MVCC | 锁类型 | 特征 |
|---|---|---|---|
| READ UNCOMMITTED | ❌ | 无锁 | 脏读可能 |
| READ COMMITTED | ✅ | 行锁 | 每次查询新快照 |
| REPEATABLE READ | ✅ | 行锁 + 间隙锁 | 默认级别,性能与一致性平衡 |
| SERIALIZABLE | ❌ | 表锁 | 串行执行,最安全 |
六、面试高频问题与答题模板
| 问题 | 答案要点 |
|---|---|
| Q1:MySQL 默认隔离级别是什么? | REPEATABLE READ。 |
| Q2:可重复读如何实现? | 固定 ReadView + MVCC。 |
| Q3:幻读是什么? | 事务中重复执行同一查询,行数变化。 |
| Q4:如何避免幻读? | InnoDB 通过间隙锁防止插入幻行。 |
| Q5:READ COMMITTED 和 REPEATABLE READ 区别? | 前者每次查询生成新 ReadView,后者只生成一次。 |
| Q6:SERIALIZABLE 的代价? | 所有操作加锁,性能最差。 |
| Q7:事务级别怎么修改? | SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
七、总结
四种隔离级别是事务控制的核心框架。
它们分别平衡了性能与数据一致性:
| 隔离级别 | 一致性 | 并发性能 | 常用场景 |
|---|---|---|---|
| READ UNCOMMITTED | 最弱 | 最高 | 日志、临时统计 |
| READ COMMITTED | 中 | 高 | Oracle 默认,OLTP 系统 |
| REPEATABLE READ | 高 | 较高 | MySQL 默认 |
| SERIALIZABLE | 最强 | 最低 | 银行、结算场景 |
一句话记住:
一致性越强,性能越低;性能越高,隔离越弱。
下一篇(第 13 篇),我将写------
《锁机制详解:行锁、表锁、间隙锁、意向锁全解析》 ,
讲透锁的类型、粒度与死锁形成条件,是 MySQL 并发控制的核心环节。