幻读(Phantom Read)是在事务并发执行时遇到的一种现象,让我详细解释:
- 什么是幻读
- 当一个事务在读取某个范围的记录时,另一个事务在该范围内插入了新记录
- 当前事务再次读取该范围的记录时,会发现多了一些原本不存在的记录
- 这种新插入的记录就像"幽灵"一样凭空出现,因此称为"幻读"
-
举例说明
-- 事务A
BEGIN;
SELECT * FROM users WHERE age BETWEEN 20 AND 30; -- 假设返回5条记录
-- 此时事务B插入了一条age=25的记录
SELECT * FROM users WHERE age BETWEEN 20 AND 30; -- 现在返回6条记录
COMMIT;-- 事务B
BEGIN;
INSERT INTO users VALUES ('Tom', 25);
COMMIT; -
防止幻读的隔离级别
- SERIALIZABLE(串行化):最高的隔离级别,可以防止幻读
- 其他隔离级别(READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ)都无法完全防止幻读
- MySQL的InnoDB在REPEATABLE READ级别下通过Next-Key Lock也能防止幻读
- SERIALIZABLE是如何防止幻读的
- 在读取数据时会自动加上范围锁
- 其他事务无法在被锁定的范围内插入数据
- 所有的操作都被序列化执行
- 注意事项
- SERIALIZABLE隔离级别性能较低
- 需要权衡系统性能和数据一致性的要求
- 在大多数应用中,REPEATABLE READ已经足够使用
- MySQL InnoDB的特殊处理
- 使用Next-Key Lock(间隙锁+记录锁)
- 在REPEATABLE READ级别下也能防止幻读
- 这是InnoDB特有的实现,其他数据库可能不同
结论:SERIALIZABLE隔离级别可以防止幻读,但在MySQL InnoDB中,REPEATABLE READ也能通过Next-Key Lock机制防止幻读。