“对每个事务取其最后一次成功获锁的时刻作为 lock point。若冲突操作使前驱图出现边 $T i\to T j$,相应不兼容锁迫使 $T i$ 的相关锁先获得并在 $T j$ 获锁前释放,…”
形式陈述 ​
在同一 事务调度 中,来自不同事务的两个操作若访问同一数据项且至少一个是写,就称冲突;读—读不冲突。两个调度冲突等价,当且仅当它们包含相同事务操作,并对每一对冲突操作保持相同先后。若调度与某个串行调度冲突等价,它就是冲突可串行化的,因而满足 可串行化 的一个可判定子类。
对有限调度
基本判据为
无环时,任一拓扑序都是一个冲突等价串行次序;有环则每条边要求的先后闭合成矛盾。该定理针对有限、事件与数据项已知的调度。构图之后的环检测是线性的,输入中的谓词访问或范围冲突怎样展开则属于额外建模成本。
充分性的证明可沿一个拓扑序进行:不断把拓扑序最前事务的操作越过与其不冲突的相邻操作,聚到调度前端,再递归处理余下事务;冲突边保证不会跨过必须保持的操作对。必要性则更直接:若与串行顺序冲突等价,每条边都必须沿该顺序前进,有限全序不可能包含有向环。
直觉
冲突操作不能随意交换:一次写若跨过另一个事务的读,读到的值可能改变;两次写互换则最终写者可能改变。非冲突的相邻操作可以逐步交换。若这些交换最终能把每个事务的操作聚成连续块,就得到了串行调度。
前驱图把大量操作压成事务级约束。边
这个抽象刻意不分析写入函数是否交换。两次都写常数 0 仍是写写冲突,因为一般判据只看访问类型;若系统要利用加法交换或集合并集等语义,必须采用有证明的语义并发控制,而不能悄悄从标准图中删边。
例子与边界
考虑
r1(x); w1(x);
r2(x); w2(y);
r3(y); w3(z);
c1; c2; c3
w3(z) 与前面不访问
另一个调度
r1(x); r2(y); w1(y); w2(x); c1; c2
在
冲突可串行化不是全部视图可串行化。盲写可能制造冲突环,却不改变任何读来源或最终写者;这类严格更宽的历史由 视图可串行化 处理。反过来,图无环只回答隔离次序,不回答读了未提交值后能否安全提交。
构图时读—写方向也不能合并。
推论与应用
构图算法可逐项扫描调度,对同一数据项的跨事务读写和写写对加入边,再做拓扑排序。实现若锁的是范围或谓词,图的“数据项”也必须覆盖幻读冲突;只按现有行 ID 构图会漏掉插入的新行。
两阶段锁等协议通过限制锁的取得与释放,让所有冲突边服从某个锁点顺序。它们提供的是充分生成机制,不是图判定的定义。对包含中止的执行,还需先说明被撤销操作怎样从逻辑调度中消除;环检测本身不会执行 undo。
在线检测可以在每次加入边后维护增量有向无环图;发现成环时中止某个尚未提交事务。选择哪个事务是代价策略,不影响判据。若环上的事务都已向外确认提交,检测已经太晚,系统不能靠事后任选一个回滚来补造串行历史。
参考资料
- Philip A. Bernstein, Vassos Hadzilacos, and Nathan Goodman, Concurrency Control and Recovery in Database Systems, Addison-Wesley, 1987, Chs. 2–3。
- Christos H. Papadimitriou, “The Serializability of Concurrent Database Updates,” Journal of the ACM 26(4), 1979, pp. 631–653。
- Hector Garcia-Molina, Jeffrey D. Ullman, and Jennifer Widom, Database Systems: The Complete Book, 2nd ed., Pearson, 2008, Ch. 18。