2020年Java面试208题 021-请说一下什么是脏读、不可重复读和幻读

本文详细解释了数据库事务中的脏读、不可重复读和幻读现象,以及它们的区别。通过四个隔离级别——读未提交、读已提交、可重复读和可串行化,阐述了如何解决这些问题。最后,介绍了间隙锁作为解决幻读问题的一种策略,确保在可重复读隔离级别下避免幻读的出现。
摘要由CSDN通过智能技术生成

2021年10月22日 星期五 晴

1. 前言

大家好,我是小崔爱读书,今天继续给您讲解《2020年Java面试208题》,本期面试官的问题是:请说一下什么是脏读、不可重复读和幻读?

2. 知识点

咱们来说说这三个问题的现象。

2.1. 脏读、不可重复读、幻读的现象是什么?

脏读:甲去查自己的账户有多少钱,乙正在修改甲的余额,乙错误多打了几个0,然后甲的余额变成了1个亿,甲一看乐疯了。乙也发现了数据错了,还好还好,乙是在事务中修改的,就赶紧回滚了。甲很开心,以为自己实现了人生小目标。乙很放心,知道甲还是一个穷逼。

这个过程中,甲读到了乙事务中修改的数据,乙又做了回滚,甲得到的数据是错误的数据,就是脏读

不可重复读:甲第二次去查自己有多少钱,他怕再出现之前那种脏读现象,因此就加了事务进行读取数据。甲事务先读了一次余额为1万元,这时候乙又来了,乙修改了甲的余额为 8000元,修改完毕后乙提交并结束了事务。这时候甲还未结束事务,在结束事务前,甲又去查看了一下自己的余额,发现数变了,少了2000块钱。甲傻眼了,加着事务呢,咋重复读了一次余额又不一样了?这就是不可重复读

幻读:甲郁闷的不行,自己的账面总是错。为了查证账目是否正确,甲决定查查自己的存取款明细。甲查看自己编号 1 - 5之间的出入账明细,看到有 4条,编号分别为 1 2 4 5,没有编号3的账目。这时候,乙悄默声的又来了,乙向甲的账目明细中插入了一条编号为3 的出账记录,并提交了事务。甲这时候又查了一次,发现账目又多了一条出账。甲又郁闷了,难道我产生幻觉了?怎么这次多了一条出账?这就是幻读

总结一下,脏读就是甲读到了乙未提交事务的数据变更,乙回滚后,数据没有变,但甲以为数据变了。不可重复读就是甲先读了一遍是正确的数据,乙对这些数据进行了修改,甲再读一次是修改后的数据,一个事务中重复多次读到的数据是不同的。幻读就是甲读到几条连续的数据,乙向这几条数据中又插入了一条新的数据,甲再读的时候发现多了一条,以为自己有了幻觉。

这么看起来,脏读、不可重复读、幻读都是多并发情况下出现的数据库问题,都是一个事务修改数据影响了另一个事务读取到数据的正确性。

2.2. 脏读、不可重复读、幻读的区别是什么?

脏读是事务A读到了事务B中未提交的数据。

不可重复读是事务A中读的数据,被事务B修改并提交了,事务A并没有保证自己读到的数据不可修改。

幻读是事务A读某个范围内的数据,这些数据没有被修改,但这些数据中被事务B插入了新数据。

2.3. 事务的隔离机制

这就有点奇怪了,事务不是有隔离性吗?既然已经隔离了,怎么数据还会被其他事务修改呢?

并且,既然三种错误都是一个事务修改数据影响到另一个事务读取数据,为什么还要分的那么细?这不就是读写冲突吗?怎么还细化出来了3种错误?

回答这两个问题,就要详细解释事务的隔离机制,不同级别的隔离机制对并发事务的数据读写错误是如何解决了。由于事务的隔离是分为不同级别的,不同的级别可以解决一部分问题,这就区分出了脏读、不可重复读和幻读的底层解决细节了。

事务隔离级别分为4种:读未提交、读已提交、可重复读、可串行化

这4种隔离级别分别在性能和高并发下数据冲突之间寻找平衡。性能越好的,高并发下数据越容易冲突,反之亦然。世界不完美,人总是在矛盾中寻找平衡。

读未提交:这种隔离级别是最轻量级别的,对数据不上锁,可以读取到其他事务未提交的事务。

因此,甲就读到了乙未提交的数据,这就是脏读

读已提交:这种隔离级别下,只能读其他事务已经提交的数据,因此读已提交隔离级别就解决了脏读问题

但是当事务A先读一次数据,然后事务B修改并提交数据,然后A再读一次数据,就会发现两次读到的数据不一样,因为事务A第一次读的时候和第二次读的时候,都是已提交的数据。因此读已提交隔离级别会造成不可重复读问题

可重复读:在可重复读隔离级别下,会对读到的数据加锁,即读的数据也不允许其他事务修改。因此可重复读隔离界别就解决了不可重复读的问题

但可重复读只对已有的数据进行加锁,并不能阻止其他事务插入新数据。如果事务A读取了两条记录,事务B向这两条数据之间又插入了一条记录并提交了事务,然后事务A再读时发现是3条数据了。因此可重复读隔离级别会造成幻读问题

可串行化:在可串行化隔离级别下,所有的事务是串行执行的,即多个事务是按照先后顺序执行的,这就可以解决了所有的脏读、不可重复读以及幻读问题。因为可串行化其实是将高并发的事务强制阻塞成单线程执行了。这绝对不会出现任何冲突问题,但也可以想象这种隔离级别的性能是超级低的。

由于可串行化的性能太差,一般很少用这种隔离级别的。那么对于幻读这种终极问题怎么解决呢?一般使用间隙锁来处理。

间隙锁:首先我们要知道,其实所有的隔离机制都是通过锁来解决问题的。通过前面的描述我们可以看到可重复读这种隔离方式其实很不错了,能解决很多问题,如果找到一个策略把幻读问题也解决了,那么可重复读隔离方式就完美了。

为了让可重复读隔离不会出现幻读问题,引入了间隙锁这个杀器。

幻读问题的根本是插入数据造成的,如果不允许插入数据自然就解决问题了。间隙锁就是把某个区间(间隙)整体上锁,这个区间的数据不仅不允许修改、删除,也不允许新增。这样就解决了幻读问题。

3. 演示面试

好的,知识点 解释完了,接下来由我来进行演示面试。

您好,面试官。

首先,脏读、不可重复读、幻读,是数据库不同事务隔离级别下产生的问题。

数据库的隔离级别有4种:读未提交,读已提交,可重复读,可串行化。

读未提交隔离级别,事务对数据不加锁,可以读取其他事务未提交的数据。假如事务A采用读未提交隔离级别,事务B正在操作数据但未提交,事务A会读到事务B的未提交数据,事务B回滚事务后,事务A读到的数据就是错误的、脏的。这就是脏读。

读已提交隔离级别,事务只能读取别的事务已经提交的数据,这就从根本上杜绝了脏读的问题,因此读已提交隔离级别就可以解决脏读的问题。但读已提交还存在不可重复读的问题。

例如事务A采用读已提交的隔离级别,它先读了一次数据,然后事务B修改了该数据,事务A又读了一次数据,发现数据变了。这是不应该的,在同一个事务中,未做数据修改操作数据居然变了,这就是不可重复读问题。

可重复读隔离界别解决了不可重复读问题,可重复读隔离级别下锁住数据后,别的事务不能对被锁的数据进行修改,这样就杜绝了不可重复读问题。

但是可重复读隔离级别还存在幻读问题。因为可重复读隔离级别只是锁住了已经存在的数据,但如果另一个事务向数据中间插入一条新数据的话是可以的。比如事务A采用可重复读隔离级别,它以为这些安全了,它查询主键在1-3 之间的数据,发现有两条记录,主键分别为 1 和 3 ,这时候事务B插入了一条主键为2 的记录并提交了事务,然后事务A又查询主键在1-3之间数据,发现有3条记录了。这就是幻读。

最高级别的隔离机制是可串行化,就是排他的,这个事务执行之后,其他事务都得等着,他执行完毕后其他事务才可以执行。由于这种排他性,可以保证一定不会出现幻读问题。但这种隔离机制会造成性能问题,因为不推荐使用。

对于幻读的解决方案,一般采用间隙锁来解决,就是在可重复读隔离级别下,采用间隙锁。幻读出现的原因就是当事务A读取某个范围的数据的时候,事务B向这个范围插入了新的数据,如果不让事务B在这个范围插入数据就可以解决幻读了。间隙锁就是把这个范围整体上锁,这样不仅存在的记录不可以修改,不存在的记录也不允许插入进来,这就解决了幻读问题。

好的,对于脏读、不可重复读、幻读这三个问题的解决方案我就说这么多。

4. 总结

本期文章就写到这里,希望对您能有所帮助,谢谢,我们下期再见。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小崔爱读书

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值