MySQL事务之幻读问题
版权声明:本文为 小异常 原创文章,非商用自由转载-保持署名-注明出处,谢谢!
本文网址:https://blog.****.net/sun8112133/article/details/89173479
文章目录
在事务的并发操作中,也就是多个事务同时对同一组数据进行操作时,可能会出现脏读、不可重复读、幻读、丢失更新这四个问题,本篇博客就来为大家讲解 幻读 问题。
一、幻读概述
幻读 就是一个事务读到另一个事务新增加并提交的数据(insert)。在同一个事务中,对于同一组数据读取到的结果不一致。比如,事务A 新增了一条记录,事务B 在 事务A 提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读出现的原因就是由于事务并发新增记录而导致的。
隔离级别 有四种,分别是:读未提交、读已提交、可重复读、序列化。
读未提交: Read Uncommitted,顾名思义,就是一个事务可以读取另一个未提交事务的数据。最低级别,它存在4个常见问题(脏读、不可重复读、幻读、丢失更新)。
读已提交: Read Committed,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。 它解决了脏读问题,存在3个常见问题(不可重复读、幻读、丢失更新)。
可重复读: Repeatable Read,就是在开始读取数据(事务开启)时,不再允许修改操作 。它解决了脏读和不可重复读,还存在2个常见问题(幻读、丢失更新)。
序列化: Serializable,序列化,或串行化。就是将每个事务按一定的顺序去执行,它将隔离问题全部解决,但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
大多数数据库默认的事务隔离级别是 Read Committed,比如 SQL Server , Oracle。但 MySQL 的默认隔离级别是 Repeatable Read。
1、事例
程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现有两条记录,共花了1.2万元,似乎出现了幻觉,这就是幻读。
2、分析
在这个事例中,事务B读取了数据,接着另一个事务A插入了一条数据。在随后的查询中,事务B就会发现多了一条原本不存在的记录,就好像发生了幻觉一样,这是由于数据新增导致的。
二、演示幻读
1、新建一个数据库(bank库),并准备一张表(account表)
2、打开两个窗口,并分别设置自动提交方式为off
show variables like 'autocommit';
– 查看当前的自动提交是否开启
set autocommit = off;
– 将自动提交关闭
3、将A窗口的隔离级别设置成 “读已提交”
注意: 虽然 “可重复读” 这种隔离级别也会发生“幻读”这个问题,但是如果设置成这种隔离级别是演示不出效果的,因为只有在多个事务并发了,才可能出现 “幻读” 问题了,但是大家要记住“可重复读”这种隔离级别也是有可能会出现“幻读”的。
select @@tx_isolation;
– 查询当前的隔离级别
set session transaction isolation level read committed;
– 设置当前会话隔离级别为“读已提交”
4、两个窗口分别开启事务
start transaction;
– 开启事务 或begin;
也可以显式开启事务
5、在B窗口新增一条数据,并提交事务
use bank
– 切换到bank数据库
insert into account values(null, 'wangwu', 1000);
– 增加一条数据
commit;
– 提交事务
6、分别在数据库和A窗口中查看数据
select * from account;
– 查看account中的全部数据
这种效果和 不可重复读 的效果是一样的。数据库和A窗口中的数据都发生了改变,因为B窗口已经提交了事务,所以数据库中的数据发生改变,是属于正常现象。但是这种事务的隔离性似乎不是太好(事务的隔离性是一个事务的执行,不受其他事务的干扰),你看,B窗口提交了事务,影响到了A窗口中数据,这种隔离级别虽然解决了 ”脏读“ 问题,但是还会引发 “不可重复读”、“幻读”及“丢失更新” 问题。
三、不可重复读和幻读的区别
不可重复读的重点是修改数据,幻读的重点是新增或者删除记录。
不可重复读,改变的是数据,数据记录总条数并没有发生改变;
幻读,改变的是数据记录总条数,原来数据的值,没有发生改变,只是新增了记录条数。
疑问:
大家可能会有这样的疑问,幻读不是因为第二次读到的结果和第一次读到的结果不一样而产生幻觉,所以叫幻读嘛?好像不可重复读也是这样的,那为什么不可重复读不叫幻读呢?那是因为大家可能忽略了一个细节,不可重复读改变的是同一条数据,而幻读改变的是数据的条数。第一次读到一条,第二次却读到了两条,好像产生了幻觉一样,所以叫幻读;而不可重复读是第一次读到这个数据的值和第二次读到这个数据的值不一样,也就是相同的数据不能重复读两次,否则会出错,所以它叫做不可重复读。
有关事务的知识可以参考我之前写的博客《【Spring4.0笔记整理十七】Spring事务详解》 及 【Spring4.0笔记整理十八】Spring事务管理详解 。