1. 事务隔离级别分类
隔离级别 | 脏读 | 不可重复读 | 幻读 | 默认实现机制 |
---|---|---|---|---|
READ UNCOMMITTED | ✔️ | ✔️ | ✔️ | 无锁,直接读取最新数据 |
READ COMMITTED (RC) | ❌ | ✔️ | ✔️ | 行锁 + 每次生成新ReadView |
REPEATABLE READ (RR) | ❌ | ❌ | ⚠️* | MVCC + 间隙锁(InnoDB默认) |
SERIALIZABLE | ❌ | ❌ | ❌ | 全表锁,强制串行执行 |
*注:InnoDB在RR级别通过间隙锁(Gap Lock)避免了幻读,但需显式加锁(如
FOR UPDATE
)才能完全规避。
2. 各隔离级别详解
2.1 READ UNCOMMITTED(读未提交)
-
特点:事务可以读取其他未提交事务的修改。
-
问题:
-
脏读:读到未提交的中间状态数据(如案例1)。
-
不可重复读 /幻读:因未隔离其他事务的修改。
-
-
适用场景:几乎无实际应用价值,仅用于测试或极低一致性要求的场景。
2.2 READ COMMITTED(读已提交)
-
特点:事务只能读取其他已提交事务的结果。
-
实现机制:
-
锁:使用行锁,写操作时锁定数据行。
-
MVCC :每次
SELECT
生成新的ReadView,确保读取已提交的最新版本。
-
-
问题:
-
不可重复读:同一事务内多次读取同一行,结果可能不同(如案例2)。
-
幻读:范围查询可能因其他事务插入新行而结果变化。
-
-
适用场景:对一致性要求适中,允许不可重复读的应用(如Oracle默认级别)。
2.3 REPEATABLE READ(可重复读)
-
特点:事务内多次读取同一数据的结果一致。
-
实现机制:
-
MVCC :事务首次
SELECT
时生成ReadView,后续读取沿用此视图。 -
间隙锁:对索引范围加锁,阻止其他事务插入新数据(如案例7)。
-
-
幻读的规避:
-
纯查询:通过MVCC的快照读避免幻读。
-
更新/加锁 :若执行
UPDATE
或SELECT ... FOR UPDATE
,间隙锁会阻止插入,彻底避免幻读。
-
-
适用场景:需要保证事务内数据一致性的场景(如MySQL默认级别)。
2.4 SERIALIZABLE(串行化)
-
特点:所有事务串行执行,完全隔离。
-
实现机制:通过全表锁或Next-Key Lock强制事务排队执行。
-
问题:并发性能极低,易导致锁竞争和超时。
-
适用场景:对数据一致性要求极高且并发量极低的场景(如金融结算)。
3. 隔离级别对比实验
实验1:不可重复读 vs 可重复读
sql
-- 会话1(事务A)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT balance FROM users WHERE id = 1; -- 结果:1000
-- 会话2(事务B)
UPDATE users SET balance = 900 WHERE id = 1;
COMMIT;
-- 会话1(事务A继续)
SELECT balance FROM users WHERE id = 1; -- READ COMMITTED下结果变为900,REPEATABLE READ仍为1000
实验2:间隙锁防止幻读
sql
-- 会话1(事务A,RR级别)
START TRANSACTION;
SELECT * FROM users WHERE age > 20 FOR UPDATE; -- 加间隙锁
-- 会话2(事务B)
INSERT INTO users (name, age) VALUES ('Eve', 25); -- 阻塞,直到事务A提交
4. 如何设置隔离级别
-
查看当前隔离级别:
sql
SELECT @@transaction_isolation;
-
设置会话级隔离级别:
sql
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-
设置全局级隔离级别(需重启生效):
sql
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
5. 隔离级别的选择建议
场景 | 推荐隔离级别 | 理由 |
---|---|---|
高并发读写,允许短暂不一致 | READ COMMITTED | 减少锁竞争,提升吞吐量 |
财务交易,需强一致性 | REPEATABLE READ | 避免不可重复读和幻读,保证事务内一致性 |
数据分析,只读查询 | REPEATABLE READ | 快照读避免锁阻塞 |
极低并发,严格数据一致性 | SERIALIZABLE | 牺牲性能换取绝对隔离 |
6. 常见问题
Q1:为什么MySQL默认使用REPEATABLE READ?
- InnoDB通过MVCC和间隙锁在RR级别实现了高效的并发控制,平衡了一致性和性能。
Q2:如何避免幻读?
- 在RR级别下,对范围查询显式加锁(如
SELECT ... FOR UPDATE
),触发间隙锁机制。
Q3:高并发场景下隔离级别如何优化?
-
若业务允许,降低至READ COMMITTED,减少锁冲突。
-
合理设计索引,缩小间隙锁的范围。
总结
理解事务隔离级别的核心在于权衡数据一致性与并发性能。通过选择合适的隔离级别、合理使用锁和MVCC机制,可以在实际业务中达到最佳效果。建议结合SHOW ENGINE INNODB STATUS
分析事务状态,优化长期运行的查询和索引设计。