事务 - 避免插入时的冲突

3
我在我的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);
    }

问题在于,如果两个客户端同时预定同一时间,就应该注册冲突。而且其中一个调用应该返回消息,即时间段已被预订。但是,如果它们正好在同一毫秒内向服务器发送请求,则不会发生这种情况。两个预订都将被保存而不会出现问题。
我可以通过进行可序列化的硬核锁定范围来解决此问题,但我相信还有更好的方法,只是我自己看不到?
在这种情况下,最佳实践是什么?

1
也许一个更通用的标题会吸引更多人来看一下? - jjj
你可以通过在数据库中添加一个约束条件来处理这个问题,该条件不允许相同的预订时间存在于表中,然后在代码中捕获异常。或者你可以创建一个队列,用新的预订填充它,并有一个消费者线程逐个插入预订。 - Stefan
@Stefan,谢谢你的建议,不幸的是,情况比那更复杂,某些情况下允许预订冲突。如果超级用户想要强制预订,或者即使不同的资源已经被预订了。 - André Snede
1
死锁应该很少见。而且它们的性能成本会降至零。如果你有很多死锁,那说明你正在操作太多数据(比如表扫描)。这种情况需要停止。在最终提交之前暂停调试器,并使用 DMVs 检查当前所有锁定。在一个健康的可序列化事务中,不应该有对象锁,只应该有少数关键锁。我将把评论编译成回答。 - usr
1
“sql server all locks dmv” 似乎是一个不错的搜索词。可以从网上获取一个随机的现成查询来开始 :) - usr
显示剩余14条评论
1个回答

1
如果两个客户端推送相同的预订时间,则应注册冲突。
如果我理解正确,您不想阻止同时进行两个预订(您告诉Stefan“超级用户”可以强制执行一个)。您只想注册冲突?
这很容易做到,但您必须使用数据库。至少,必须有某种真实仲裁者,某个唯一的地方只有一个时间和对事物状态的最终理解。通常,这是数据库。逻辑看起来像这样:
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,时间,优先级}作为参数传递,然后完成。顺便说一下,以防有帮助,这种方法有一个名称:乐观并发。幸运的是,这个术语可能会在您的环境文档中出现。

我已经转向其他项目,所以这不再是一个问题。但我喜欢这个解决方案。 - André Snede

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接