MySQL 的 SERIALIZABLE(串行化) 是最高的事务隔离级别。它通过强制事务串行执行来完全避免脏读、不可重复读和幻读,但会显著降低并发性能。
核心机制
在 InnoDB 中,SERIALIZABLE 的实现方式如下:
-
自动对普通
SELECT加锁 :所有普通的
SELECT语句都会被隐式转换为SELECT ... LOCK IN SHARE MODE(共享锁)。读取的每一行都会加锁,直到事务结束才释放。 -
当前读(
SELECT ... FOR UPDATE/SHARE、UPDATE、DELETE) 的行为与 REPEATABLE READ 下一致,仍然使用行锁 + 间隙锁(Next-Key Lock)。 -
锁冲突导致等待或超时 :
如果一个事务要读取某行,而另一个事务正在修改(持有排他锁),则读取事务必须等待。同样,修改操作也必须等待其他事务释放共享锁。
与 REPEATABLE READ 的关键区别
| 特性 | REPEATABLE READ | SERIALIZABLE |
|---|---|---|
普通 SELECT |
快照读(无锁,基于 MVCC) | 加共享锁(当前读) |
| 并发读-读 | 无阻塞 | 无阻塞(共享锁兼容) |
| 并发读-写 | 读不阻塞写(快照读) | 读阻塞写(写事务等待读事务释放共享锁) |
| 并发写-读 | 写阻塞其他写,但不阻塞快照读 | 写阻塞读(读事务等待写提交) |
| 幻读处理 | 当前读用间隙锁避免,快照读无幻读 | 所有读都是当前读,自然无幻读 |
| 性能 | 较高 | 较低(大量锁等待) |
使用场景与注意事项
-
何时使用:只有在需要绝对数据一致性且并发极低的场景(如财务对账、某些批量操作)才考虑使用。多数情况下 REPEATABLE READ 已足够安全。
-
死锁风险增加:由于加锁范围更广,事务之间更容易形成死锁。
-
如何启用:
sqlSET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- 或 SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE; -
默认隔离级别:MySQL 默认是 REPEATABLE READ,而不是 SERIALIZABLE。
简单示例说明阻塞
sql
-- 事务 A
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT * FROM user WHERE id = 1; -- 对 id=1 的行加共享锁
-- 事务 B(此时执行会阻塞,直到事务 A 提交或回滚)
BEGIN;
UPDATE user SET name='new' WHERE id = 1; -- 需要排他锁,被 A 的共享锁阻塞
总结:SERIALIZABLE 通过让所有读操作都加锁来获得最高隔离性,但会严重限制并发,通常只在对数据一致性要求极高且写入很少的场景下使用。对于绝大多数应用,使用 InnoDB 默认的 REPEATABLE READ 即可获得足够的一致性保障。