事务隔离级别和MVCC

事务并发执行时遇到的一致性问题

脏写

如果一个事务修改了另一个为提交事务修改过的事务,就意味着发生了脏写现象。我们可以把脏写现象简称为P0.假设现在事务T1和T2并发执行,它们都要访问数据项x(可以把数据项x当作一条记录的某个字段)。那么P0对应的操作执行序列如下所示:

p0: w1[x]...w2[x]...((c1 or a1) and (c2 or a2) in any order)

其中w1[x]表示事务T1修改了数据项x的值,w2[x]表示T2修改了数据项x的值,c1表示事务T1的提交(Commit),a1表示事务T1的中止(Abort),c2表示事务T2的提交,a2表示事务的中止,...表示其他的一些操作。从P0到操作执行序列中可以看出,事务T2修改了未提交事务T1修改过的数据,所以发生了脏写现象。

脏写现象可能引发一致性问题。比方说事务T1和T2要修改x和y这两个数据项(修改不同的数据项就相当于修改不同记录的字段),我们的一致性需求就是让x的值和y的值始终相同。现在并发执行事务T1和T2,它们的操作执行序列如下所示:

w1[x=1]w2[x=2]w2[y=2]c2w1[y=1]c1

很显然事务T2修改了尚未提交的事务T1的数据项x,此时发生了脏写现象。如果我们允许脏写现象的发生,那么在T1和T2全部提交之后,x的值是2,而y的值却是1,不符合 "x的值和y的值始终相同" 的一致性需求。

另外脏写现象也可能破坏原子性和持久性。比如说有x和y这两个数据项,它们初始的值都是0,两个并发执行的事务T1和T2有下面的操作执行序列:

w1[x=2]w2[x=3]w2[y=3]c2a1

也就是T1先修改了数据项x,然后T2修改了数据项x和数据项y,然后T2提交,最后T1中止。现在的问题是T1中止时,需要将它对数据库所做的修改回滚到该事务开启时的样子,也就是将数据项x的值修改为0。但是此时T2已经修改过数据项x并且提交了,如果要将T1回滚的话,相当于要对T2对数据库所做的修改进行部分回滚(部分回滚是指T2只回滚对x做的修改,而不回滚对y做的修改),这就影响到了事务的原子性。如果要将T2对数据库所做的修改全部回滚的话,那么明明T2已经提交了,它对数据库所做的修改应该具有持久性,怎么能让一个未提交的事务将T2的持久性破坏呢?所以这时候就会很尴尬。

脏读

如果一个事务读到了另一个未提交修改过的数据,就意味着发生了脏读现象,我们可以把脏读现象简称为P1。假设现在事务T1和T2并发执行,它们都要访问数据项x。那么P1对应的操作执行序列如下所示:

P1: w1[x]...r2[x]...((c1 or a1) and (c2 or a2) in any order)

脏读现象也可能引发一致性问题。比如说事务T1和T2中要访问x和y这两个数据项,我们的一致性需求就是让x的值和y的值始终相同,x和y的初始值都是0.现在并发执行事务T1和T2,它们的操作执行序列如下所示:

w1[x=1]r2[x=1]r2[y=0]c2w1[y=1]c1

很显然T2是一个只读事务,依次读取x和y的值。可以由于T2读取的数据项x是未提交事务T1修改过的值,所以导致最后读取x的值为1,y的值为0。虽然最终数据库状态还是一致的(最终变为了x=1,y=1),但是T2却得到了一个不一致的状态。数据库的不一致状态是不应该暴露给用户的。

P1代表的事务的操作执行序列其实是一种脏读的广义解释,针对脏读还有一种严格节食。为了与广义解释进行区分,我们把脏读的严格解释称为A1,A1对应的操作执行序列如下所示:

A1: w1[x]...r2[x]...(a1 and c2 in any order)

也就是T1先修改了数据项x的值,然后T2又读取了未提交事务T1针对数据项x修改后的值,之后T1中止而T2提交。这就意味着T2读取到了一个根本不存在的值,这也是脏读的严格解释。很显然脏读的广义解释是覆盖严格解释包含的范围内的。

不可重复度

幻读

你可能感兴趣的:(事务隔离级别和MVCC)