我在我的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硬核锁定范围来解决这个问题,但我确信有更好的方法,而且我太盲目了,不能看到它?
在这种情况下,最佳做法是什么?
答案 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,时间,优先级}作为参数,然后您就完成了。
顺便说一句,如果有帮助,这种方法有一个名称:乐观并发。幸运的是,该术语可能会出现在您的环境文档中。