关于c#:交易-避免插入时发生冲突

Transactions - Avoid collisions on insert

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

我的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
    }

问题是,如果两个客户推送相同的预订时间,则应记录一个冲突。并且其中一个呼叫应返回一条消息,说明该时隙已被预订。但是,如果它们完全正确地击中服务器,则不会(相同的错误)。两次预订都可以毫无问题地保存。

我可以通过执行可序列化的硬核锁定范围来解决此问题,但是我敢肯定有更好的方法,而且我实在是太盲目了吗?

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


if two clients push the same booking time, a conflict should be registered

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

这很容易完成,但是您必须使用数据库。至少,必须有一些真理的仲裁者,在某个地方,只有一次,并且对事物的状态有了最终的了解。通常,这就是数据库。逻辑看起来像这样

1
2
3
4
5
6
7
8
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,time,priority}作为参数传递,就可以了。

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