结论先行:
在 MySQL 的 InnoDB 中,SERIALIZABLE 隔离级别确实可以避免幻读;
但在 SQL 标准层面,SERIALIZABLE 的定义是“可串行化”,并不天然保证避免幻读,是否避免取决于具体数据库的实现方式。
下面分层说明。
**幻读(Phantom Read)**指的是:
同一个事务中,两次执行同样的 范围查询,第二次读到了第一次没有的行。
示例:
-- 事务 A
SELECT * FROM orders WHERE amount > 100;
-- 事务 B 插入一条
INSERT INTO orders VALUES (..., 200);
-- 事务 A 再查一次
SELECT * FROM orders WHERE amount > 100;
第二次查询多了一行 → 幻读
SQL 标准定义:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | ✅ | ✅ | ✅ |
| READ COMMITTED | ❌ | ✅ | ✅ |
| REPEATABLE READ | ❌ | ❌ | ✅ |
| SERIALIZABLE | ❌ | ❌ | ❌ |
⚠️ 注意:
SQL 标准只是说“现象级别”,并没有规定如何实现。
原因:
示例:
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT * FROM orders WHERE amount > 100;
-- 锁住 (100, +∞) 的范围
此时其他事务:
INSERT INTO orders VALUES (..., 200); -- 会被阻塞
✅ 幻读不会发生
SELECT:快照读,不防幻读SELECT ... FOR UPDATE / LOCK IN SHARE MODE:所以:
| 隔离级别 | 是否避免幻读 | 说明 |
|---|---|---|
| READ COMMITTED | ❌ | 无间隙锁 |
| REPEATABLE READ | ⚠️ | 快照读不行,当前读可以 |
| SERIALIZABLE | ✅ | 强制当前读 + 锁 |
| 数据库 | SERIALIZABLE 实现 | 幻读 |
|---|---|---|
| MySQL InnoDB | 锁(Next-Key Lock) | ✅ 避免 |
| PostgreSQL | 快照 + 事务冲突检测 | ✅ 避免 |
| Oracle | 多版本 + 锁 | ✅ 避免 |
⚠️ Oracle 的 SERIALIZABLE ≠ 加锁,而是通过“写冲突回滚”实现。
✅ 在 MySQL InnoDB 中:SERIALIZABLE 能避免幻读
✅ 本质是:通过范围锁(Next-Key Lock)阻止其他事务插入
但你要知道:
SERIALIZABLE ≠ 所有数据库都用锁防幻读
如果你愿意,我可以:
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。