所以我在一个注入控制器的单例服务中有这样的函数。
public async Task<ResponseModel> Put(BoardModel request)
{
var board = await dbService.GetBoardAsync(request.UserId, request.TargetId, request.Ticker);
// Update the model
// ...
var response = await dbService.SetBoardAsync(request.UserId, request.TargetId, request.Ticker, request);
return new ResponseModel
{
ResponseStatus = response.Successful(replacements: 1) ? ResponseStatus.Success : ResponseStatus.Failure
};
}
我担心的是竞争条件,比如说该函数的两个实例同时运行,并且一个覆盖数据库中的条目。
这可能吗?它发生的可能性非常小,但我仍然有点担心。
谢谢!
答案 0 :(得分:1)
是的,假设您的服务器有多个线程(可以是任何支持生产的Web服务器),那么两个或多个线程可以同时运行相同的代码块。处理这种情况的典型方法是乐观并发。这意味着EF将尝试保存记录(乐观地假设它能够没有问题),并且如果记录最终在它到达之前被修改,它将返回例外(特别是OptimisticConcurrencyException
)。您可以查看this ASP.NET getting started article以了解如何设置它的演练。本质上,它只涉及向数据库表添加rowversion
列。每次更新行时,该列的值都会发生变化。因此,EF可以检查其尝试使用当前桌面上的内容进行更新的记录上的值。如果它们相同,则可以继续更新。如果没有,那么其他东西修改了记录并停止更新。通过捕获返回的异常,您可以通过重新加载数据并尝试进行另一次更新来做出适当的响应。
你最不可能会多次遇到并发问题,但为了以防万一,我建议使用类似Polly(Nuget)之类的东西来处理异常。除此之外,它允许您重试一定次数甚至永远,直到没有异常引发。这样就可以确保记录最终得到更新,即使存在多个并发冲突。
Policy
.Handle<OptimisticConcurrencyException>()
.RetryForever((exception, context) => {
// resolve concurrency issue
// See: https://msdn.microsoft.com/en-us/data/jj592904.aspx
})
.Execute(() => {
db.SaveChanges();
});