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}作为参数传递,就可以了。
顺便说一句,如果有帮助,此方法的名称是:乐观并发。幸运的是,该术语可能会在您的环境文档中出现。