多个/快速的ajax请求和实体框架的并发问题



我有一个 asp.net 的MVC4应用程序,我正在使用Unity作为我的IoC。我的控制器的构造函数接收一个存储库,该存储库接收一个工作单元(DBContext)。一切似乎都很好,直到来自同一会话的多个 ajax 请求发生得太快。由于并发问题,我收到Store update, insert, or delete statement affected an unexpected number of rows (0)错误。这是从 ajax 请求调用的方法的样子:

public void CaptureData(string apiKey, Guid sessionKey, FormElement formElement)
{
        var trackingData = _trackingService.FindById(sessionKey);
        if(trackingData != null)
        {
             formItem = trackingData.FormElements
                          .Where(f => f.Name == formElement.Name)
                          .FirstOrDefault();
             if(formItem != null)
             {
                formItem.Value = formElement.Value;
                _formElementRepository.Update(formItem);
             }
        }
}

仅当 ajax 请求快速发生时,才会发生这种情况,这意味着快速发生。当请求以正常速度发生时,一切似乎都很好。就像应用程序需要时间来赶上一样。不确定我需要如何处理存储库中的并发检查,以免错过更新。另外,我尝试将"MultipleActiveResultsSets"设置为true,但这没有帮助。

正如您在评论中提到的,您使用的是行版本列。此列的要点是防止同一行的并发覆盖。您有两个操作:

  • 读取记录 - 读取记录和当前行版本
  • 更新记录 - 使用指定的键和行版本更新记录。行版本自动更新

现在,如果这些操作通过并发请求执行,您可能会收到以下内容:

  • 请求 A:读取记录
  • 请求 B:读取记录
  • 请求 A:写入记录 - 更改行版本!
  • 请求 B:写入记录 - 触发异常,因为在读取记录期间检索的行版本的记录不存在

触发该异常是为了告诉您您正在尝试更新过时的数据,因为已存在更新记录的新版本。通常,您需要刷新数据(通过从数据库重新加载当前记录)并尝试再次保存它们。在高并发方案中,此处理可能会重复多次,因为您的数据库只是为了防止这种情况而设计的。您的选择是:

  • 删除行版本,并让请求根据需要覆盖该值。如果您确实需要并发请求处理,并且您很高兴拥有"一些"值,那么这可能是要走的路。
  • 不允许并发请求。如果您需要处理所有更新,则很可能还需要它们的实际顺序。在这种情况下,应用程序不应允许并发请求。
  • 请改用 SQL/存储过程。通过使用表提示,您将能够在读取操作期间锁定记录,并且在第一个请求保存更改和提交或回滚事务之前,没有其他请求能够读取该记录。

最新更新