什么是幻读
1. 举个例子
定义表结构如下:
代码语言:javascript复制CREATE TABLE `t` (
`id` int(11) NOT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);
- T1 时刻查询到的数据为id=5这行数据
- T2 时刻将id=0的数据的d置为5
- T3 时刻查询到的数据为id=0,id=5的数据
- T4时刻插入新的数据 (1,1,5)
- T5时刻查询到的数据为id=0,id=1,id=5,
其中T5时刻查询到了id=1的现象称为幻读,而查到id=0不能称为幻读。这是因为幻读的定义为幻读指的是两次查询同一个范围的数据,后一次查询到了前一次没有查询到的数据,就好像出现了幻觉,所以称为幻读。需要注意的是,幻读只有在当前读的时候才会出现,而且幻读专指新插入的行。
2. 幻读带来的问题
- 破坏了锁的语义。当实行 select ... from... where ... for update 的时候,语义是要锁住符合条件的行,但是幻读破坏了这个规则。
- 数据不一致。两次同样的范围查询却查出来的结果不一样。
3. 如何解决幻读
答案是使用间隙锁。在两两数据行之间有间隙,如果我们能把数据行之间的间隙也锁住,则不会有产生幻读的数据插入。
间隙锁和行锁合称为next-key lock ,实现语句为 select * from t for update。这样表t中数据行被锁住,而且行与行之间的间隙也会被锁住。
4. next-key lock 带来的问题
next-key lock 会导致锁的范围变大,影响并发,而且有可能会带来死锁。