
MySQL 的事务隔离级别定义了事务在并发执行时,彼此之间的可见性以及可能遇到的并发问题(脏读、不可重复读、幻读)。SQL 标准定义了四个隔离级别,MySQL 的 InnoDB 存储引擎支持所有这些级别,并在默认的 REPEATABLE READ
级别下提供了额外的保证。
以下是 MySQL 四个事务隔离级别的详细说明、可能引发的问题以及 InnoDB 的具体实现行为:
| READ UNCOMMITTED | 可能 | 可能 | 可能 | |
| READ COMMITTED | 不可能 | 可能 | 可能 | SELECT都生成新 Read View (快照),看到的是最新已提交的数据。使用 MVCC 和 记录锁 (无间隙锁)。 |
| REPEATABLE READ | 不可能 | 不可能 | 可能(理论) | 默认级别SELECT时生成 Read View,后续复用。使用 MVCC 和 Next-Key Locking (记录锁+间隙锁)。InnoDB 通过 Next-Key Lock 在 当前读场景下避免了幻读。 |
| SERIALIZABLE | 不可能 | 不可能 | 不可能 | SELECT自动转为 SELECT ... LOCK IN SHARE MODE,加共享锁,读写严重互斥,并发性最低。不使用 MVCC 快照读。 |
关键概念解释:
脏读 (Dirty Read):
一个事务读到了另一个未提交事务修改的数据。
危害: 读取到可能被回滚的无效数据,导致业务逻辑错误。
解决:
READ COMMITTED
及以上级别避免。不可重复读 (Non-Repeatable Read):
在同一个事务内,两次读取同一条记录,得到了不同的结果(因为其他事务在中间修改并提交了该记录)。
危害: 破坏了事务内数据一致性预期。例如,事务内基于第一次读的值做计算,第二次读时值变了。
解决:
REPEATABLE READ
及以上级别避免 (通过 MVCC 的快照或锁)。幻读 (Phantom Read):
在同一个事务内,两次执行相同的查询,得到了不同的结果集(因为其他事务在中间插入或删除了符合查询条件的记录并提交)。
危害: 范围查询的结果集不稳定,影响统计、分页等操作。
注意点: SQL 标准中
REPEATABLE READ
允许幻读。但 InnoDB 在REPEATABLE READ
级别下通过Next-Key Lock
机制,在当前读
(SELECT ... FOR UPDATE
,UPDATE
,DELETE
) 场景下避免了幻读。对于快照读
(SELECT
),因为读取的是事务开始时的快照,理论上不会看到新插入的数据(即不会“幻象”),但如果后续在同一个事务内执行了会修改数据的操作(当前读),再执行快照读,可能会看到新插入的数据(MVCC 可见性规则决定的),这种现象有时也被称为幻读的一种表现,但严格来说与 SQL 标准定义的幻读(两次查询结果集不同)略有区别。SERIALIZABLE
则完全避免。
InnoDB 各隔离级别的具体实现细节:
READ UNCOMMITTED:
行为: 事务可以看到其他事务尚未提交的修改。直接读取数据页上的最新值。
问题: 脏读、不可重复读、幻读都可能发生。
使用场景: 极少使用,除非对数据一致性要求极低且追求极致性能(但通常得不偿失)。
设置:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
或SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;READ COMMITTED (RC):
行为:
使用 MVCC:每次执行普通的
SELECT
语句(快照读)时,都会生成一个新的 Read View。因此,它总是能看到查询开始前最新已提交的数据。对于
SELECT ... FOR UPDATE
,UPDATE
,DELETE
(当前读):只会锁定涉及到的具体行记录(记录锁),不会加间隙锁 (Gap Locks) 或 Next-Key Locks。优点:
避免了脏读。
锁的粒度相对较小(无间隙锁),减少锁冲突,提高并发性能(尤其在写冲突不高的场景)。
可以看到其他事务已提交的新数据。
问题:
不可重复读: 事务内两次读同一行,如果中间有其他事务提交了修改,结果可能不同。
幻读 (可能): 因为不加间隙锁,其他事务可以插入新的记录到查询范围内并提交,导致后续查询看到新行。
使用场景: 需要避免脏读,可以接受不可重复读和可能的幻读。常用于报表查询、数据导出、对一致性要求不是极高但并发要求较高的 OLTP 场景。Oracle 默认级别。
设置:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
或SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
3. REPEATABLE READ (RR):
行为 (默认级别):
使用 MVCC:在事务中第一次执行快照读 (
SELECT
) 时生成一个 Read View。整个事务期间,后续所有的快照读都复用这个相同的 Read View。因此,事务内看到的是一致的历史快照。对于
SELECT ... FOR UPDATE
,UPDATE
,DELETE
(当前读):使用 Next-Key Locking 算法(记录锁 + 间隙锁)。这不仅能锁定查询命中的记录,还能锁定记录之间的间隙,阻止其他事务在查询范围内插入新的记录。优点:
避免了脏读。
避免了不可重复读 (MVCC 快照)。
在当前读操作 (
FOR UPDATE
,UPDATE
,DELETE
) 下避免了幻读 (Next-Key Lock)。这是 InnoDB 对 SQL 标准的扩展增强。对于纯快照读 (
SELECT
),因为始终读取事务开始时的快照,理论上不会看到新插入的数据(“幻象行”)。问题:
使用 Next-Key Lock 会增加锁的范围和锁冲突的概率,可能降低并发写入性能。
长事务可能导致大量旧版本数据无法被 Purge,占用 Undo Log 空间。
使用场景: MySQL InnoDB 的默认级别。适用于需要高度数据一致性、对不可重复读和幻读有要求的场景,如金融交易、账户管理等。也是大多数应用推荐的级别。
设置: (默认级别,通常无需显式设置)
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
或SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
4. SERIALIZABLE:
行为:
不使用 MVCC 的快照读。所有普通的
SELECT
语句自动隐式转换为SELECT ... LOCK IN SHARE MODE
。这意味着读取会加共享锁 (S Lock)。
写操作(
UPDATE
,DELETE
,INSERT
,SELECT ... FOR UPDATE
)仍然需要获取排他锁 (X Lock)。优点: 完全避免了脏读、不可重复读、幻读。提供了最强的隔离性。
缺点:
并发性最低。读写严重互斥(S 锁阻塞 X 锁请求,X 锁阻塞所有锁请求),容易导致大量锁等待和性能下降。
死锁风险增加。
使用场景: 对数据一致性要求极高,且可以接受极低并发性能的场景。实际应用中非常少见。
设置:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
或SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
如何设置和查看隔离级别?
查看全局/会话隔离级别:
SELECT @@GLOBAL.transaction_isolation, @@SESSION.transaction_isolation;-- 或 (旧变量名,8.0+ 推荐用上面的)SELECT @@GLOBAL.tx_isolation, @@SESSION.tx_isolation;
设置全局隔离级别 (重启后生效,影响后续所有新会话):
SETGLOBAL transaction_isolation ='READ-COMMITTED';
设置当前会话隔离级别 (仅影响当前连接):
SET SESSION transaction_isolation = 'REPEATABLE-READ'; -- 或 'READ-COMMITTED'等
设置下一个事务的隔离级别:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;START TRANSACTION; -- 下一个开始的事务将使用此级别
选择建议:
优先使用
REPEATABLE READ
(默认): 它在保证良好一致性的同时提供了不错的并发性能。InnoDB 通过 MVCC 和 Next-Key Lock 巧妙地解决了大部分并发问题。考虑
READ COMMITTED
的场景:对不可重复读和幻读不敏感的应用。
需要看到最新已提交数据的报表查询或只读从库。
写冲突较少,且希望减少锁争用、提高并发写入吞吐量。
使用基于语句的复制 (SBR) 时,主从切换可能更安全(但推荐使用基于行的复制 RBR)。
避免使用
READ UNCOMMITTED
和SERIALIZABLE
: 前者牺牲一致性,后者牺牲性能,除非有非常特殊的需求。
重要提示:
隔离级别的选择需要在数据一致性和并发性能之间做权衡。没有绝对的最佳,只有最适合当前业务场景的。
理解不同级别下 MVCC 和 锁机制(尤其是 Next-Key Lock 在 RR 下的作用)的行为是掌握隔离级别的关键。
在
REPEATABLE READ
下,长事务可能导致 Undo Log 膨胀和锁持有时间过长,需注意管理事务边界。即使使用了较高的隔离级别,良好的数据库设计(合理索引、避免全表扫描)和事务设计(短事务、按相同顺序访问资源)对避免死锁和性能问题至关重要。




