数据库事务的ACID隔离级中P0(脏写)和P4(更新丢失)的区别

有很多人在学习数据库的事务特性即ACID时对隔离级很糊涂,特别是不能区分脏写(P0)和更新丢失(P4)的异同,本文对这两个异常做一下解释,希望能够对研究数据库事务的人士有所帮助。


P0(Dirty Wirte),即脏写。可以表示为w1[x]...w2[x]... (c1 or a1)

P4(Lost Update),更新丢失。表示为r1[x]...r2[x]w2[x]c2...w1[x]c1


上面表达式的区别为:

P0:在事务T1写入操作w1[x]和提交操作(c1 or a1)之间,被写入了事务T2的数据;P4:在事务读取操作r1[x]和写入操作w1[x]之间写入了另外事务T2的数据。


上面表达式的含义为:

P0(脏写):写入和提交之间,又别写入了别的数据。能带来的后果为两个:

1、不能保证数据的一致性。比如数据库中需要满足x=y,接下来有下面的操作w1[x] w2[x] w2[y] c2 w1[y] c1。T1的操作是x=1,y=1;而T2的操作是x=2,y=2,而上面的结果为x=2,y=1,破坏了数据的一致性。

2、如果T1回滚或T2回滚,不能。假如x初始值为0,T1写入了x=1,T2写入了x=2,此时x的临时结果为2,如果T1回滚,那么x回复为初始值0,那么当T2提交时x仍为0;如果T2回滚,那么也回到初始值为0,接下来当T1提交时,x值仍为0。


P4(更新丢失):其含义为T1要更新x的数据,其首先读取x的值,然后再该值上加1再写回数据库。但是在读取x后,T2写入了新的x并成功提交,而T1还是在老的x值的基础上加1。这样,T2的更新对于T1而言就像被丢弃了一样。


P4提出的目的是让数据自动提供“有状态更新”。例如,事务T1想先读取x当前的数值,如果x为100,则在此基础上把x加20,但如果在这中间有另一个事务T2更改了x的值并提交,那么T1的判断就应该失效了。但是写锁机制下,以及mysql的repeatable read都不能屏蔽这个异常,因为他们只在写操作时才开始上锁。


要注意的是,能够protect from P0的隔离级,不一定能够屏蔽P4。比如最基本的锁系统,为了防止P0的发生会在T1开始写入操作时加锁,这样P0遍不会发生,但是P4因为是读取操作,并不会加锁,T2还是可以写入成功。


微软提出的Snapshot Isolation(SI)是可以屏蔽P4异常的,因为SI在提交时会检查整个事务过程中是否有有别事务写入,如果有则回滚。因此SI不同于传统的写锁机制(只是写操作开始时才上锁)。当然mysql可以使用一些方法来达到类似的效果,例如读取数据的select末尾加上FOR UPDATE。


实际上,写操作可以分为两类,一类为上面所述的我们称之为有状态更新,因为其基于数据原有值的更新;另一类我们称之为无状态更新,有的学者也称之为盲写(BlindWrite)。对于无状态更新的并发写入,我们其实并不应该加锁限制。SI在这方面并没有加以优化。


我带领小组设计并实现的SSCC可以有效的防止上面的异常发生,简单的说,SSCC通过两类不同的写操作来屏蔽P4。感兴趣的话可以访问SSCC的github页面:https://github.com/domino-succ/domino/wiki/%E4%B8%AD%E6%96%87-%E7%AE%97%E6%B3%95%E8%AE%BE%E8%AE%A1,也可以下载代码。有问题请联系我Professor Zhang:zhangtiey@gmail.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值