最近复习mysql, 复习到事务那块, 对于幻读和不可重复读这块的概念老是搞不清。

今天专门说说这个幻读。

说到这个, 我们先讲讲事务那块存在的问题。
当两个不同mysql用户对同一张表的数据访问时存在的问题。

下面的所有情况都是两个mysql用户同时开始事务begin。
以mysql用户A和mysql用户B为例。

1、脏读
用户B对这个表的数据进行修改。在没有commi提交之前, 用户A可以看到修改后的数据。 也就说B用户对这个表数据的任何操作A都是能看到的 - 这就是脏读。

为什么说是脏读?
个人理解, 在commit提交之前的操作都是存在未知性的。 有可能用户A看到的操作, 用户B回滚(我们都知道开启事务,在没有commit之前这些操作是没有真正写入磁盘上的, 可以通过回滚回到begin之前的状态)。用户B都不确定的操作, 用户A却信以为真。 很显然是有问题的。

2、不可重复读
用户B对表的中数据进行操作,在commit之前,用户A看不到, 但是在commit之后,用户A是可以看到的。

举个例子:
表中有个数据val = 20; 一开始A和B读到的这个数据都是20。 用户B对这个数据修改val = 40,
在没有commit之前, 用户读到的val还是20.
在commit之后, 用户读到的val为40。

个人理解:
由于只是简单的了解,没有真正意义上遇到这个业务处理。做一个猜想。
用户A就是要用val=20, 原表中的数据进行业务处理。 如果因为用户B对这个数据进行了修改, 导致用户A读到val != 20, 可能会导致业务处理问题。

3、幻读

幻读我先不讲,因为结合后面的事务隔离级别讲会更加清晰。

事务隔离级别

1、读未提交(read uncommited)
既没有解决脏读、 不可重复读、幻读问题。

也就是说这个级别: 用户B在没有commit提交之前的所有操作, 用户A是可以读到的。

2、读已提交(read commited)
解决了脏读。
但是没有解决不可重复读、幻读问题,

也就说这个级别: 用户B不会存在脏读, 用户B 在commit提交之前的操作,用户A是看不到的。
但是commit提交之后, 用户A是可以看到的。

3、可重复读(repeatable read)
解决了脏读、不可重复读。
但是没有解决幻读问题。 这也是解释幻读的地方。

也就是说这个级别:
用户B 在commit提交之前的对于数据的修改, 在commit提交前后, 用户A都是看不到的。也就说不存在脏读、不可重复读。

但是请注意, 我在这块加黑的话-数据的修改。 我没有说操作,操作可能包含数据的修改和添加新的数据。

如果这块用户B在表中添加了一行新的数据(添加或删除),commit提交之后,用户A提交之后确是可以看到的。 – 这就是没有解决幻读问题。

举个例子:
用户B在表中添加了val1 = 77, 在commit提交之后, 用户A发现表种怎么多了val1==77这个数据??? 就像幻觉一样。

这也就是幻读和不可重复读的区别:
不可重复读是对于数据的修改。
幻读是对于数据的添加或删除。

4、可串行化
它解决了所有的问题,但是它是性能最差的。
他就像一个单线程,后续一个事务的执行必须等待前一个事务执行完毕。