并发控制技术手段之快照隔离(四)

若是说数据在 ACID 特性(带有了并发控制技术)的保护下会发生不一致的现象,那么:web

    ACID 和快照隔离级别技术(多版本)的保护下,是否是数据就必定再也不会产生不一致的现象呢 sql

    答案是否认的。数据库系统中数据的异常,在多种并发控制技术中已经被解决,但这不代表全部的异常都已经被解决,更不代表再也不有新的异常被发现。数据库

    咱们知道,数据库并发控制技术中有一个大名鼎鼎的技术,称为快照隔离( Snapshot Isolation ),这项技术解决了读写冲突,在保证数据不会产生前面两节提到的读异常和写异常的状况下,使得读写互不阻塞(两阶段锁技术读写操做互相阻塞),提升了并发度。并发

    注意咱们这里谈到的多版本是“ multi-version ,简称 MV ”,其相对于“ single-valued ,简称 SV ”,这个多版本是快照隔离并发控制技术中的数据项有多个版本,其含义仅此而已。快照隔离并发技术是(  Multiversion concurrency control MVCC )技术的一种,二者都要基于“数据项存在多个版本”,但与多版本并发控制技术相比二者是有区别的(具体区别参见 2.2 节对并发控制技术的探讨)。ide

    快照隔离并发控制技术的缺点,是并不能真正保证事务为“可序列化的”,即事务间的并发操做依旧会引起数据异常现象,可是这里的数据异常现象区别于前面提到的各类异常现象,其异常现象是“业务的逻辑语义”引起的,即除了抽象的读写操做,数据间还应该知足必定语义,即约束( constraint )。post

    在快照隔离并发控制技术中并发的事务因不知足约束而发生的异常,成为“写偏序( Write Skew )”,这样的异常有两种,参见    1-   4ui

1-4 写偏序异常的两种状况     [1]     spa

两个事务写偏序   postgresql

三个事务写偏序   xml



T1

T2

T1

T2

T3

t0

x       ← SELECT COUNT(        ?      

)

FROM doctors

WHERE on

     ?      call = true    


x       ←

SELECT

current_batch

     





t1

x       ← SELECT COUNT(        ?      

)

FROM doctors

WHERE on

     ?      call = true    


INCREMENT
current_batch




t2

IF x        ≥ 2 THEN        

UPDATE doctors

SET on

      ?       call = false      WHERE name = Alice    


Commit




t3

IF x        ≥ 2 THEN        

UPDATE doctors

SET on

      ?       call = false      WHERE name = Bob    


x       ←

SELECT

current_batch

     





t4

Commit

SELECT SUM(amount)

FROM

WHERE batch = x

     ?      1    





t5

Commit

COMMIT




t6

INSERT INTO receipts
VALUES (x, somedata)





t7

COMMIT





说明:

 q     表格头两行,代表写偏序异常现象的两种状况,分别是由两个事务引起异常、三个事务引起异常。  

 q      表格第一列,时间值列,代表时间值在逐渐增加,即 t0<t1<t2<t3<t4<t5<t6<t7 。  

 q      对于每一种异常现象,都分为 2 个列,分别是两个并发的事务,各自命名为 T1 事务和 T2 事务。  

 q      对于二个事务引起的异常现象(简单写偏序, Simple Write Skew ):    按照时间顺序, T1 事务在 t0 时刻读取了在打电话的值班医生个数, T2 事务在 t1 时刻也读取了在打电话的值班医生个数。事务 T1t2 时刻进行判断:若是在打电话的值班医生个数大于等于 2 人则请 Alice 中止打电话。事务 T2t3 时刻进行判断:若是在打电话的值班医生个数大于等于 2 人则请 Bob 中止打电话。而后事务 T1T2 分别提交。若是在这种并发的状况下,容许事务 T1T2 都提交成功,则 t6 时刻, AliceBob 都中止了打电话。若是串行执行事务,先执行事务 T1 后执行事务 T2Alice 会中止打电话但 Bob 不会中止,这与前一种状况的结果不一样;若是先执行事务 T2 后执行事务 T1Bob 会中止打电话但 Alice 不会中止,这与前一种状况的结果也不一样;这代表前一种并发执行是非序列化的,即事务 T1T2 并发时违反了约束( 约束为 :若是同时打电话的人数大于等于 2 人则请 AliceBob 其中一我的中止打电话直到同时打电话的人数少于 2 人)发生了写偏序异常现象。对于简单写偏序,能够用一个形象化的图表示,参见图 1-1 。  

 q      对于三个事务引起的异常现象( Batch Processing ):    对于这种状况,后两个并发更新事务 T3T2 是可串行化的且不存在任何异常,可是一个只读事务 T1 出如今某个时刻却可能正好形成问题。所出现的问题是这样的,当事务 T3 提交时, T2 处于活跃状态,这时,事务 T1 启动要读取事务 T2T3 涉及的数据(  current_batch  和 receipts   ),这时,事务 T1 的快照包括了事务 T3 的插入后的结果(由于 T3 已经提交);可是,事务 T2 没有提交,它的插入操做数据不包含在事务 T1 的快照中。在优先图(如图 1-2 )中会形成一个环(有关如何造成这样的环),  说明这样的 调度是非可串行化的  。  

1-1 两个事务引起的异常现象优先图

NvuQbeZ.jpg%21web

1-2 三个事务引起的异常现象优先图

3A7vyin.jpg%21web

     本节所述的这两种状况,若是使用优先图表示,均可以在参与操做的事务之间,画出一个环,存在环说明: 调度是非可串行化的。 为解决这样的问题,这就要求数据库引擎必须在事务提交时而不是在快照上检查完整性约束以免本节所述的不一致现象。  

注意:

    更多的写偏序异常示例,能够参见: https://wiki.postgresql.org/wiki/SSI#Read_Only_Transactions

    [1]     示例源自论文: Dan R. K. PortsKevin GrittnerSerializable Snapshot Isolation in PostgreSQL

备注:转载自:http://www.tuicool.com/articles/bEBRzyM