如果这个问题的答案取决于 DMBS,我很想听听 Oracle 11g 或更高版本和 SQL Server 2012 的答案。
我们有一个表,它有一个引用自身的外键:
CREATE TABLE Versions (
Id INT IDENTITY(1,1) NOT NULL,
[Date] DATETIME NOT NULL,
BasedOnVersion INT NULL -- foreign key that references Versions
)
我们有将新记录插入Versions
表中的存储过程。如果它们同时运行,我们需要确保没有两个版本引用相同的另一个版本,因此版本层次结构中不能有任何分叉(除非我们故意创建一个分叉):
How it should run
Transaction 1 reads current version 17
Transaction 1 writes new version 18 based on 17
Transaction 2 reads current version 18
Transaction 2 writes new version 19 based on 18
How it should NOT run
Transaction 1 reads current version 17
Transaction 2 reads current version 17
Transaction 1 writes new version 18 based on 17
Transaction 2 writes new version 19 based on 17
在第二种情况下,我们有两个基于相同版本的版本。
所以我们需要一种方法来序列化这两个事务。首先,我们想到了使用ISOLATION LEVEL SERIALIZABLE
,但隔离级别对 没有任何影响INSERTs
,因此它们不是解决方案。
Versions
另一种方法是在事务开始时获取表上的锁。这可能适用于 SQL Server,但不适用于 Oracle,因为 OracleLOCK TABLE IN EXCLUSIVE MODE
不会阻止事务 2 读取表。
那么这种问题的最佳解决方案是什么?