【JavaWeb】为什么会出现脏写、脏读、不可重复读与幻读

一、为什么会出现脏写、脏读、不可重复读与幻读

我们平时的业务系统和数据库的连接并不是单个,一般都会同时有多个线程操作数据库,也就可能会出现多个线程同时操作同一个数据的情况,而且很多操作一般都是以事务的方式进行,可以借助redo log重做或者undo log回滚,如果是单个事务,肯定是没有什么问题的,但是如果是多个事务就会发生一些奇怪的现象。

二、脏写是怎么出现的?

在这里插入图片描述
现在有事务A和事务B两个事物,他们会操作同一个数据C,A先将C改成了A,然后B又将值改成了B,然后事务B提交了。还记得事务A在修改数据时会写一条undo log日志吧,在B事务提交之后,A事务如果发生回滚,就回执行undo log中的内容,将值变回C。这样就很奇怪了,这对于事务A来说好像没什么影响,但是对于事务B来讲,他之前对这条数据所做的操作仿佛没有做过,这就是脏写。

​ 脏写的本质就是事务B在事务A提交之前对相同数据的写操作因为事务A的回滚而失效

在这里插入图片描述
站在发生时间的角度去观察,大概就是上图的样子,简而言之就是在其他事物提交之前发生的写操作因为回滚而失去作用,就是脏写(前提条件是两个事物都修改了相同的数据)

三、脏读是怎么回事?

其实脏读和上面介绍的脏写原理类似。

​ 同样两个事物A和事务B,A将数据C更新为A,然后此时B事务读取到了这行数据,它的值为A,然后B事务就拿去用了,出乎意料的是A事务此时来了一个回滚操作,让B事务之前所读取到的A值成为了无效的值,这对于事务B来说就发生了脏读,如下图所示:
在这里插入图片描述
不知道聪明的你是否发现脏写和脏读的共同之处?

  • 发生的原因都是另一个事物通过undo log进行回滚所导致的
  • 对相同的数据做了操作
  • 脏读和脏写所操作的数据也叫做脏数据(在内存中修改了还未及时刷入磁盘的数据)

四、什么是不可重复读?

之前的脏读问题可以通过如下限制阻止其发生——每个事物只能看见其他事物已经提交的数据,对于已经修改但是未提交的数据是看不见的。但是仅仅是这样就万事大吉了吗?我们来看看下面的这种情况:

​ 事物A先读取数据C
在这里插入图片描述
之后事物B修改了这个值,将其改为了B然后B事物提交了
在这里插入图片描述
A事物此时再次读取这个值的时候会发现前后两次读取值竟然不一样!

在这里插入图片描述对于A事务,在事务提交前对同一个数据读取了多次,发现读取的值并不都是一样的,这种现象就叫做不可重复读,顾名思义就是不能重复地读取到一样的值

五、幻读又是怎么回事?

从名字可以猜出个大概,应该是读出的结果让人感觉就像是出现了幻觉一样,那究竟是怎么回事呢?下面通过一个场景来说明一下

​ 现在有一个事物A,执行select * from xxx where age < 50从数据库读取了20条数据

在这里插入图片描述
此时事务A还没有执行完,然后又来了一个事务B,事务B往这个表中插入了5条age小于50的数据,像下面这样:
在这里插入图片描述
接着,事务A再次执行select * from xxx where age < 50,此时查询出来了25条数据,事务A一看,怎么前后两次查询到的数量不一样?惊讶程度就像是你从口袋里掏钱,第一次掏出来50块钱,第二次再掏兜的时候发现有150块,那你很可能会怀疑自己是不是出现幻觉了。
这种前后两次读取的数据量不一致的情况就叫做幻读

六、小结

今天给大家介绍了脏写、脏读、不可重复度以及幻读分别是怎么产生的及其特点,今后将会去介绍MySQL是使用什么样的方法去避免上述情况的发生的,今天的内容先介绍到这里,如果本篇文章有需要补充或者纠正的地方的话还希望能指出

猜你喜欢

转载自blog.csdn.net/wang_qiu_hao/article/details/125216950
今日推荐