文章目录
什么是幻读
可重复读隔离下为什么会产生幻读?
MySQL中如何实现可重复读
如何解决幻读
什么是幻读
先来看看事务的隔离级别
然后,谈幻读之前,我先说说我对幻读的理解:
所谓幻读,重点在于“幻”这个词,很梦幻,很玄乎,真假不定,就像蒙上了一层雾一样,你不能真真切切的看到对方,给人以幻的感觉,这便是“幻”。而所谓的幻读,也就是你通过SELECT查询出来的数据集并不是真实存在的数据集,你通过SELECT语句查询出某条记录是不存在的,但是它有可能在真实的表中是存在的。
我是这么理解幻读与不可重复读的:
幻读说的是存不存在的问题:原来不存在的,现在存在了,则是幻读
不可重复读说的是变没变化的问题:原来是A,现在却变为了B,则为不可重复读
幻读,目前我了解的有两种说法:
说法一:事务 A 根据条件查询得到了 N 条数据,但此时事务 B 删除或者增加了 M 条符合事务 A 查询条件的数据,这样当事务 A 再次进行查询的时候真实的数据集已经发生了变化,但是A却查询不出来这种变化,因此产生了幻读。
这一种说法强调幻读在于某一个范围内的数据行变多或者是变少了,侧重说明的是数据集不一样导致了产生了幻读。
说法二:幻读并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:A事务select 某记录是否存在,结果为不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。产生这样的原因是因为有另一个事务往表中插入了数据。
我个人更赞成第一种说法。
说法二这种情况也属于幻读,说法二归根到底还是数据集发生了改变,查询得到的数据集与真实的数据集不匹配。
对于说法二:当进行INSERT的时候,也需要隐式的读取,比如插入数据时需要读取有没有主键冲突,然后再决定是否能执行插入。如果这时发现已经有这个记录了,就没法插入。所以,SELECT 显示不存在,但是INSERT的时候发现已存在,说明符合条件的数据行发生了变化,也就是幻读的情况,而不可重复读指的是同一条记录的内容被修改了。
举例来说明:说法二说的是如下的情况:
有两个事务A和B,A事务先开启,然后A开始查询数据集中有没有id = 30的数据,查询的结果显示数据中没有id = 30的数据。紧接着又有一个事务B开启了,B事务往表中插入了一条id = 30的数据,然后提交了事务。然后A再开始往表中插入id = 30的数据,由于B事务已经插入了id = 30的数据,自然是不能插入,紧接着A又查询了一次,结果发现表中没有id = 30的数据呀,A事务就很纳闷了,怎么会插入不了数据呢。当A事务提交以后,再次查询,发现表中的确存在id = 30的数据。但是A事务还没提交的时候,却查不出来?
其实,这便是可重复读的作用。
过程如下图所示:
上图中操作的t表的创建语句如下:
CREATE TABLE t
(
id
int(11) NOT NULL,
c
int(11) DEFAULT NULL,
d
int(11) DEFAULT NULL,
PRIMAR