我读过很多资料,他们说在数据库中实现可序列化的方法之一是使用两阶段锁定。但是我真的不明白在Jim Gray 的这个例子中两阶段锁定如何确保可序列化。
一个例子是我们在数据库中有两行,一行的值为white,另一行的值为black。我有两笔交易:
- TX1 会将白色的值更新为黑色
- TX2 会将黑色的值更新为白色
如果TX1和TX2同时执行,则TX1获取值为white的行锁,TX2获取值为black的行锁。所以没有锁定冲突,最终,值被交换了。
我读过很多资料,他们说在数据库中实现可序列化的方法之一是使用两阶段锁定。但是我真的不明白在Jim Gray 的这个例子中两阶段锁定如何确保可序列化。
一个例子是我们在数据库中有两行,一行的值为white,另一行的值为black。我有两笔交易:
如果TX1和TX2同时执行,则TX1获取值为white的行锁,TX2获取值为black的行锁。所以没有锁定冲突,最终,值被交换了。
单独的两相锁定 (2PL) 不足以确保可串行化。由于它允许在我们的事务结束之前释放写锁,系统还必须跟踪其他事务,这些事务的写集与我们事务的写集重叠。那些其他事务的结果取决于我们的事务是提交还是回滚。
强严格两阶段锁定 (SS2PL) 持有所有读取和所有写入锁,直到我们的事务结束。其他事务无法获取我们已经锁定的对象的锁定。因此,无需跟踪重叠的写入集,因为现在这种事情是不可能的。
可序列化隔离级别不允许幻像行。所以我们的事务使用的锁的类型也很重要。一种方法是使用键范围锁而不是单键锁。
这里有一些涵盖该主题的讲座幻灯片。2PL 从幻灯片 18 左右开始,尽管 1-17 是很好的背景。它们包括许多交易时间表,这些时间表逐步说明了注意事项。
在某些 DBMS 中,SS2PL 不会阻止这种异常。我能想到的原因包括定义、实现和谓词。
可序列化的学术定义是,它必须看起来好像一个事务在另一个事务开始之前就已经完成了。然而,SQL 标准将其定义为“无幻象行”。这些是不等价的。两者之间的差距就是这种异常蔓延的地方。
高吞吐量是一件好事。所以 DBMS 设计者倾向于尽可能少地锁定。在这种情况下,它将是一个“白色”行(或另一笔交易的“黑色”行)。这允许异常。如果锁定在表而不是行上,可能是因为锁定升级,就不会有异常。但是,对每个查询都这样做会降低性能。
所写的更新声明只有白行应该变成黑色。对于那些以黑色开头的行,它没有什么可说的。如果程序员的意图是在查询提交后每一行都应该具有相同的颜色,那么可以通过省略 WHERE 来明确显示。我相信现有的 SS2PL 锁定实现将提供所需的可序列化结果。(并不是说程序员在这里有错,只是显示另一个差距。)
我想系统有可能跟踪每个事务的写谓词并回滚任何与先前提交的事务重叠的谓词。到您已经实现了 MVCC 方法的大部分方法时,所以随它去吧。