这是不可重复读取的情况吗?

时间:2013-08-12 09:09:39

标签: concurrency isolation-level

我有以下表格(这里以实体框架为模型,但我的问题与EF无关):

enter image description here

如您所见,这是一个版本化的Product表。 Id列是主键,但组合(EntityId, VersionId)也可以是主键。 EntityId表示实体的Id,它在实体的不同版本之间保持不变。通过使用IsDeleted = 1写一行来删除实体。

负责数据操作的存储过程首先检查数据操作是否正常。例如,UPDATE SP检查实体是否已被删除。如果这些检查成功,则SP在Version表中生成一个新行,然后在Product表中生成一个新行:

(pseudo-code):

sp_Product_Update:
(1) IF EXISTS (SELECT Id FROM Product WHERE IsDeleted = 1 AND EntityId = @ProductId)
        RAISERROR "Entity has already been deleted"
        RETURN
(2) INSERT INTO Versions ...
(3) INSERT INTO Product ... (IsDeleted = 0)

sp_Product_Delete:
(1) IF EXISTS (SELECT Id FROM Product WHERE IsDeleted = 1 AND EntityId = @ProductId)
        RAISERROR "Entity has already been deleted"
        RETURN
(2) INSERT INTO Versions ...
(3) INSERT INTO Product ... (IsDeleted = 1)

这很有效。

目前,我正在分析这个并发问题。想象一下以下并发场景,其中同一个实体同时调用两个SP:

Transaction 1                          Transaction 2
sp_Product_Update                      sp_Product_Delete

(1) Check succeeds, entity has not yet been deleted.

                                       (1) Same check.

                                       (2) INSERT INTO Versions...
                                       (3) INSERT INTO Product.. (IsDeleted = 1)

(2) INSERT INTO Versions...
(3) INSERT INTO Product ... (IsDeleted = 0)

正如您所看到的,此竞争条件会导致数据不一致,即IsDeleted = 0 IsDeleted = 1条目之后

因此,我们必须确定避免这种竞争条件所需的隔离级别。

  • 这似乎不是 Dirty Read ,因为(1)中读取的数据不脏。
  • 它不是不可重复读,两个事务中都没有两个读取。
  • 同样适用于幻影阅读,两个交易中都没有两个查询。

所以我有两个问题:

  • 我的分析是否正确?
  • 需要什么样的隔离级别才能避免此类问题?

1 个答案:

答案 0 :(得分:1)

您的解决方案需要可序列化的隔离级别,因为所有命令都需要作为一个原子操作一起执行。

如果您不使用存储过程,我建议使用专为高吞吐量的此类情况设计的optimistic locking