事务的隔离级别(Isolation Level)是指:多个事务并发执行时,数据库为保证事务隔离所采取的措施强度。不同的隔离级别会影响系统的并发性能和数据一致性。
在 MySQL(InnoDB 引擎)中,一共有四种标准隔离级别:
🔒 MySQL 的四种事务隔离级别
隔离级别 | 能解决的问题 | 可能发生的问题 | 并发性 |
---|---|---|---|
读未提交(Read Uncommitted) | - | 脏读 | 高 |
读已提交(Read Committed) | ✅ 脏读 | 不可重复读 | 较高 |
可重复读(Repeatable Read)【MySQL 默认】 | ✅ 脏读 ✅ 不可重复读 | 幻读 | 中等 |
串行化(Serializable) | ✅ 脏读 ✅ 不可重复读 ✅ 幻读 | - | 低(性能最差) |
📖 各隔离级别详解 + 场景举例
① 读未提交(Read Uncommitted)
- 读未提交是最低的隔离级别,在这个级别,当前事务可以读取未被其他事务提交的数据,以至于会出现“脏读”(允许读取未提交的数据)、“不可重复读”和“幻读”的问题。
- 场景:一个事务读取了另一个事务未提交的修改,如果对方回滚,你就读到了不存在的数据!
举例:
T1: UPDATE account SET balance = balance - 100 WHERE id = 1; // 还没提交
T2: SELECT balance FROM account WHERE id = 1; // 看到减少后的余额
T1: ROLLBACK; // 回滚
➡️ T2 读到的是一个“假的余额”,这就是脏读。
② 读已提交(Read Committed)
- 在读已提交级别,当前事务只能读取已经被其他事务提交的数据
- 避免了脏读
- 但是:一个事务中两次读取同一条记录,结果可能不同(不可重复读),不可重复读和幻读问题仍然存在。
举例:
T1: SELECT balance FROM account WHERE id = 1; // 余额 = 1000
T2: UPDATE account SET balance = 800 WHERE id = 1;COMMIT;
T1: SELECT balance FROM account WHERE id = 1; // 余额 = 800
➡️ T1 两次读到不同值,称为不可重复读
③ 可重复读(Repeatable Read)⭐MySQL 默认
- 可重复读:一个事务在执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,一个事务内多次读取的结果一致
- 防止脏读 + 不可重复读
- 但可能发生幻读:新增记录可能“凭空”出现!
举例:
T1: SELECT * FROM user WHERE age > 18; // 查出10条
T2: INSERT INTO user (name, age) VALUES ('张三', 20);COMMIT;
T1: 再次 SELECT * FROM user WHERE age > 18; // 看到11条
➡️ 出现了“幻影”数据 —— 这就是幻读。
⚠️ 但是!InnoDB 使用间隙锁(Gap Lock)避免了幻读的发生,所以MySQL 实际上避免了幻读!
④ 串行化(Serializable)
- 最严格的隔离级别
- 每个事务串行执行,完全锁表
- 避免所有并发问题:脏读、不可重复读、幻读
- 会导致大量的锁竞争问题,性能极差,几乎不适用于高并发
🎯 Mermaid 图:事务隔离级别与并发问题对照图
下面这张图可视化地表示了各种隔离级别与并发问题之间的关系:
🧠 面试延伸点 & 易错点
Q1:为什么 MySQL 默认使用 Repeatable Read?
它在性能和一致性之间做了最佳平衡。配合 MVCC(多版本并发控制) 和 间隙锁,可以防止大部分问题。
Q2:怎么解决幻读?
MySQL 的 InnoDB 使用 间隙锁(Gap Lock) 来锁住可能插入的位置,从而避免幻读。
Q3:MVCC 适用于哪个隔离级别?
只适用于 Read Committed 和 Repeatable Read,因为它依赖多版本快照来读取旧数据。
Q4:A 事务未提交,B 事务上查询到的是旧值还是新值?
在 MySQL 的默认隔离级别(可重复读)下,如果事务 A 修改了数据但未提交,事务 B 将看到修改之前的数据。
这是因为在可重复读隔离级别下,MySQL 将通过多版本并发控制(MVCC)机制来保证一个事务不会看到其他事务未提交的数据,从而确保读一致性。
Q5:怎么更改事务的隔离级别?
使用
SET SESSION TRANSACTION ISOLATION LEVEL
可以修改当前连接的隔离级别,只影响当前会话。
使用SET GLOBAL TRANSACTION ISOLATION LEVEL
可以修改全局隔离级别,影响新的连接,但不会改变现有会话。