漫画:如何给新来的妹子解释什么是数据库的脏读、不可重复读和幻读

640?wx_fmt=gif

640?wx_fmt=png

本文经授权转载自漫话编程(ID:mhcoding)

快春节了,可我仍在公司加班时,这时候,组内新来的萌妹实习生过来问我:

师兄,AbstractPayExecutor这个类你改了代码了?

640?wx_fmt=png

是呀,我刚刚修改了代码并提交到GitLab上


640?wx_fmt=png

我说的呢,刚刚看到的一个常量没有了

640?wx_fmt=png

我忘记和你说,这不是出现了不可重复读现象么

640?wx_fmt=png

师兄你说的可是数据库的读现象?

能给我讲讲吗,我不是很懂这个知识点

640?wx_fmt=png

“读现象”是多个事务并发执行时,在读取数据方面可能碰到的状况。了解它们有助于理解各隔离级别的含义。其中包括脏读、不可重复读和幻读。


640?wx_fmt=png

事务隔离级别


在数据库中,事务是要满足ACID的,即满足原子性、一致性、持久性以及隔离性。

在数据库事务的ACID四个属性中,隔离性是一个最常放松的一个。可以在数据操作过程中利用数据库的锁机制或者多版本并发控制机制获取更高的隔离等级。

但是,随着数据库隔离级别的提高,数据的并发能力也会有所下降。所以,如何在并发性和隔离性之间做一个很好的权衡就成了一个至关重要的问题。

你说的这个我明白,但是具体的隔离级别和读现象有什么关系呢?

640?wx_fmt=png

不同的隔离级别会导致和解决不同的读现象,我先给你介绍下都有哪些读现象

640?wx_fmt=png

脏读

第一种读现象叫做脏读,顾名思义,就是读到了脏数据,即无效数据。

脏读。是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交(commit)到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

打个比方,什么情况下会出现脏读呢,就是我在我的本地修改了AbstractPayExecutor这个类的代码,我还没提交。

为了更快的知道这个类被我改成了什么样,你跑到我的电脑前面阅读了我修改后的代码。这就是脏读了。因为我没有提交代码,说明我随时可能撤销刚刚的修改,这时你之前读取到的数据就是脏数据了。

这种情况下,多个开发者之间的并发性很高,几乎没有任何阻塞。师妹想知道代码最新的是什么样,她就读到了最新代码。但是,这个代码我还没有提交,这就是个脏数据。我们之间的隔离性很差。

这显然不是我们想要看到的现象啊。

640?wx_fmt=png

是的,我们不希望代码在未提交

的状态下被别人读到

640?wx_fmt=png

那脏读这种情况实在是太不应该了

640?wx_fmt=png

是的,接着我们看下提高一点隔离性

640?wx_fmt=png

不可重复读

为了解决脏读问题,我们决定提高一点隔离性,我在修改代码的时候,不允许她跑到我的电脑前面读代码。她只能读取到我提交后的代码。

当我需要修改AbstractPayExecutor这个类的时候,我需要告诉师妹让她等一下,等我提交完代码她再读。这就有效的解决了脏读,因为师妹读到的代码全部都是我已经提交的代码。

但是,提高了我们之间的隔离性,并发性就降低了一些。因为她要等我提交代码后才能阅读。

这样是好了一些,不会出现脏读了

640?wx_fmt=png

脏读没有了,但还会存在不可重复读问题

640?wx_fmt=png

不可重复读是像AbstractPayExecutor常量被删除的现象吗

640?wx_fmt=png

差不多

640?wx_fmt=png

我们已提高了一点隔离级别,使得脏读现象没有了。但是并没有办法避免以下现象:

师妹在阅读AbstractPayExecutor的代码,代码中定义了一个LOGGER常量。然后我修改了代码,把这个常量删除了,并提交。师妹更新了代码继续阅读,但是她却发现LOGGER这个常量没有了。

两次读取,得到的文件内容不一样。严重了影响了她的学习进度。这就是不可重复读现象。

不可重复读。是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。

幻读是不可重复的一种特殊场景。

哦,原来这就是不可重复读

640?wx_fmt=png

师兄,有没有可能我再读某个类的代码的时候,你先不要修改这个类呢?

640?wx_fmt=png

可以呀。这就是进一步提升了隔离性了

640?wx_fmt=png

幻读

为了让师妹可以更好的学习代码。我们约定好,当她阅读某个类的代码的时候,她通知我以下,然后我就不修改这个类的代码。避免出现不可重复读的情况。

这样,我们之间的并发性就又降低了一些。不仅仅她阅读哪个类有了一些限制,我修改哪个类也有了要求了。

就这样相安无事了一段时间,师妹又来找我了。

师兄呀,你又新增了几个类了?刚刚我看的时候只有20几个类呀

640?wx_fmt=png

是的,我又增加了2个枚举类和1个Java类

640?wx_fmt=png

那我只能继续阅读这几个新增的类了

640?wx_fmt=png

在提升了隔离性之后,虽然我不会修改师妹正在阅读的类,师妹也不会阅读我正在修改的类。但是我可能会增加或者删除几个类。这时候和师妹之前读取到的类的总个数就有了变化。也就是说,她之前读到的数据就不准确了。这就是幻读。

幻读。指同一个事务内多次查询返回的结果集不一样(比如增加了或者减少了行记录)。比如同一个事务A内第一次查询时候有n条记录,但是第二次同等条件下查询却又n+1条记录,这就好像产生了幻觉。

我明白了。原来这就是幻读。

640?wx_fmt=png

是的,幻读的情况其实也是可以解决的。

640?wx_fmt=png

我知道如何解决,就是我读代码的时候你不要做任何修改

640?wx_fmt=png

额,是的

640?wx_fmt=png

如果想要解决幻读问题,那么就只能在师妹阅读代码的时候,我什么也不做了。这样我们之间的隔离性最高,但是并发性就最低了。

要想解决脏读、不可重复读、幻读等读现象,那么就需要提高事务的隔离级别。但与此同时,事务的隔离级别越高,并发能力也就越低。所以,还需要读者根据业务需要进行权衡。


640?wx_fmt=png

总结


事务的隔离性上,从低到高可能产生的读现象分别是:脏读、不可重复读、幻读。

脏读指读到了未提交的数据。

不可重复读指一次事务内的多次相同查询,读取到了不同的结果。

幻读师不可重复读的特殊场景。一次事务内的多次范围查询得到了不同的结果。

通过在写的时候加锁,可以解决脏读。

通过在读的时候加锁,可以解决不可重复读。

通过串行化,可以解决幻读。

以上这几种解决方案其实是数据库的几种隔离级别。

640?wx_fmt=png640?wx_fmt=jpeg

640?wx_fmt=gif

 热 文 推 荐 

便利蜂“高数裁员”开天下先河!

年薪 10 万的程序员,如何积累人生的第一个 100 万?

小心!你的脸正在成为色情片主角

鏖战九载,Google 是否会因 Oracle 而弃用 Java?

iPhone曝严重漏洞,用户接听FaceTime前或被“监听”!

聊聊云计算:为什么构建网站时常会用到负载均衡

年度大戏!以太坊大神怒怼智能合约之父,尼克·萨博到底做错了啥?

嫁人当嫁程序员

 
 

print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"

640?wx_fmt=gif点击“阅读原文”,打开 CSDN App 阅读更贴心!

640?wx_fmt=png 喜欢就点击“好看”吧


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值