事务 - 避免插入时发生冲突

时间:2015-05-11 22:59:41

标签: c# asp.net-mvc database entity-framework transactions

我在我的asp.net应用程序中使用EF6,我有一个问题,这有点烦人,我似乎无法找到一个很好的解决方案。

我的代码如下所示:

using (var scope = TransactionScopeUtil.RepeatableReadMaxTimeoutRequired())
{
    bool hasConflict = await BookingService.HasConflictAsync(newBooking);
    if (!hasConflict)
    {
        await BookingRepository.InsertAsync(newBooking);
        return Json(AjaxPayload.Success());
    }
    else
    {
        return Json(AjaxPayload.Error());
    }
}

    // The transaction scope builder:
    public static TransactionScope ReadCommittedMaxTimeoutRequired()
    {
        return new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
        {

            IsolationLevel = IsolationLevel.ReadCommitted,
            Timeout = TransactionManager.MaximumTimeout
        }, TransactionScopeAsyncFlowOption.Enabled);
    }

问题是,如果两个客户推送相同的预订时间,则应注册冲突。其中一个调用应返回一个消息,表明时间段已经被预订。但如果他们完全正确地击中服务器(在相同的milis中)则不会。两个预订都保存没有问题。

我可以通过执行Serializable硬核锁定范围来解决这个问题,但我确信有更好的方法,而且我太盲目了,不能看到它?

在这种情况下,最佳做法是什么?

1 个答案:

答案 0 :(得分:1)

  

如果两个客户推送相同的预订时间,则应注册冲突

如果我理解正确,您不希望同时阻止两次预订。 (你告诉Stefan a"超级用户"可以强迫一个。)你只想注册一个冲突?

它很容易完成,但你必须使用数据库。至少,必须有一些真理的仲裁者,一些单独的地方只有一次和最终理解事物的状态。通常,这是数据库。逻辑看起来像这样

insert into T values (X, time, priority = 1) where X not in T
if rows_affected = 1
    hurrah
else 
    while rows_affected < 1
       priority = max(priority) + 1
       insert into T values (X, time, priority) where (X, priority) not in T
   register conflict, you are $priority in line

将其转换为SQL或您正在使用的任何内容,传递{X,时间,优先级}作为参数,然后您就完成了。

顺便说一句,如果有帮助,这种方法有一个名称:乐观并发。幸运的是,该术语可能会出现在您的环境文档中。