阅读 A Critique of ANSI SQL Isolation Levels

目录

ANSI隔离级别定义

锁与异常场景

快照隔离SI(Snapshot Isolation)

总结

文章对隔离级做了很清晰的梳理。本文稍作总结。感兴趣的还是建议阅读一遍原文。

ANSI隔离级别定义

文章主要是对ANSI SQL的隔离级别进行补充。

在进行补充之前的,分别给出了脏读(A1,P1),不可重复读(A2,P2),幻读(A3,P3)的读写序列化定义,大概知道是定义了上面三种异常场景即可。

A1: w1[x]...r2[x]...(a1 and c2 in either order) (Dirty Read)

A2: r1[x]...w2[x]...c2...r1[x]...c1 (Fuzzy or Non-Repeatable Read)

A3: r1[P]...w2[y in P]...c2....r1[P]...c1 (Phantom)

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

P2: r1[x]...w2[x]...((c1 or a1) and (c2 or a2) any order)

P3: r1[P]...w2[y in P]...((c1 or a1) and (c2 or a2) any order)

为什么有狭义,广义的定义,因为存在场景,狭义定义不符合,需要对其扩展的。如关于脏读狭义定义,是指一个事务写后即被其他的事务读取,而写事务随后终止,即造成了脏读。实际上,写事务不需要回滚(范例H1,中写事务1未回滚),读事务只要能读到未提交数据,即完成脏读了。

H1: r1[x=50] w1[x=10] r2[x=10] r2[y=50] c2  r1[y=50] w1[y=90] c1

结合ANSI SQL隔离定义的表格,就很清楚了。从表格看,似乎解决了幻读,就能够达到串行化读的,但实际上,作者发现了些其他的异常场景,因此后续就是对隔离级别进行补充。

锁与异常场景

“Granularity of Locks and Degrees of Consistency in a Shared Data Base” 这篇文章给出异常场景和锁的一个关系。

首先对的Well-formed进行一下解释,所谓的Well-formed writes(read)就是指在读或者写之前,都会获取相应的锁,并且完成操作后会释放该锁。一个事务是Well-formed的是指,该事务分为两个阶段加锁和释放锁阶段。加锁阶段只能够加锁,释放锁阶段只能够释放锁,这也是所谓的2阶段封锁(2PL)。其中short duration指该锁能够释放阶段释放。而long duration是指该锁保留至事务结束后一并释放。

本质上,一种异常现象能够对应上一种加锁的策略,下面对几种异常都简单描述一下。

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

如本文提出的脏写的异常,对应表格Degree 0。脏写,写后写。意味着一个事务对数据修改完成之后,未提交之前就释放了写锁,该写锁是short duration的写锁。

可以看出,Degree0以后的,全部都是long duration的写锁,不存在脏写的情况。

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

对于脏读,对应degree 1。原因就是读取的时候无需获取锁。因此一个事务修改完一个数据之后,另外一个事务能够看到的修改后的数据。

P2: r1[x]...w2[x]...((c1 or a1) and (c2 or a2) any order) 不可重复读

不可重复读,对应degree 2,读的时候需要加上一个short duration读锁。保证了不出现脏读,保证read committed。但是由于是short duration的读锁,意味着该数据不是全程在读锁的保护之下,期间就有可能会被其他的事务进行修改。随后该事务重新获得数据的读锁,发现前后两次查询的数据不一致。

P3: r1[P]...w2[y in P]...((c1 or a1) and (c2 or a2) any order) 幻读

可重复读,对应REPEATABLE READ部分。对于查询到的数据,加的是long term的读锁,对范围查询,加了short term的读锁。这能够解决之前不可重复读的问题,因为查询到的数据加的是直至事务结束的读锁,其他事务无法修改。

但是对范围查询加的是short term的读锁,导致区间是不受保护的。两次对同样区间的读,其间可能会有其他事务在这个区间插入数据,导致两次读取仍然数据不一致,出现幻读。

可重复读,仍然是不可重复读,看来只是大家一致延续这样的一种说法。

mysql的可重复读没有幻读。对于快照读,快照不存在幻读的情况;对于当前读,通过gap lock来保证区间也是上锁的。

P4: r1[x]...w2[x]...w1[x]...c1 更新丢失

本文提出的一种异常。更新被覆盖。解决了P2(那就是在RR下)就能够解决P4,解决了P1(那就是在RC下)还是会出现P4,P4是处在RC和RR之间的异常。这种是一种cursor的常见使用场景,对cursor增加一个读锁,来规避这种问题。解决P4的隔离状态称为Cursor Stability。

快照隔离SI(Snapshot Isolation)

以上都是通过锁来对应确定一个隔离级别。但是锁开销比较大,因此有通过快照来实现事务的隔离。接下来探讨的就是SI出于什么隔离级别。

当一个事务开启的时候有事务开启的时间戳,提交的时候有提交的时间戳。该事务能够成功提交,当且仅当这个时间段内没与其他事务提交过包含该事务修改过的数据的写事务。

对于一个多版本的读写序列,总是能够映射成一个单版本的序列。

H1.SI: r1[x0=50] w1[x1=10] r2[x0=50] r2[y0=50] c2 r1[y0=50] w1[y1=90] c1(其中x0,x1中的0,1指的是x的不同版本)

上面的多版本序列可以改为一个单板本序列,如下。

H1.SI.SV: r1[x=50] r1[y=50] r2[x=50] r2[y=50] c2 w1[x=10] w1[y=90] c1
 

但是并不意味着快照读就是可串行的。如下H5,假定x+y存在必须为正的约束,在快照隔离下,会存在违反约束的情况。

H5: r1[x=50] r1[y=50] r2[x=50] r2[y=50] w1[y=-40] w2[x=-40] c1 c2

因此提出了新的问题A5,关注的是数据约束上的问题,下面是两种异常的定义。

A5A Read Skew

r1[x]...w2[x]...w2[y]...c2...r1[y]...(c1 or a1)

A5B Write Skew

r1[x]...r2[y]...w1[y]...w2[x]...(c1 and c2 occur)

总的来说,两种异常都是指多个数据之间存在约束,但是从一个事务的层面看,事务完成后,发现违反了约束了。

接下来,在不同的隔离级别上看这两种异常。对于RR模式,RR模式对于读锁的长期的读锁,规避了不可重复度的问题,因此能够规避A5A,A5B这两个问题。而在RC模式,这两种问题都可能会出现的。

所以这两种异常是处于RC和RR模式之间的异常场景。

对于快照隔离SI,快照隔离保证了不会出现脏读,所以SI是不弱于RC的,而在SI模式,A5A是能够规避的,因为第一个事务的开启的时候,就会记录时间戳,这期间修改的数据是不可见的, 因此的y还是在事务开启时候的y,x与y的约束是没有破坏的。因此SI的隔离级别大于RC。

上面分析RR模式是能够解决的A5B异常的,但是SI隔离级别无法解决A5B。所以RR不弱于SI。

我们知道,RR模式是无法解决幻读的问题(A3)。但是SI下,不会出现幻读的问题,因为读取数据是根据时间戳来判断是否可见。因此SI不弱于的RR。

综合来看,SI与RR模式是不可比的。文章还给出了一个关于各隔离级别的关系图示。

总结

1)提出了一些新的异常情况,补充并纠正了ANSI划分的隔离级别。

2)分析了基于MVCC的快照隔离的隔离级别。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值