1

我有一个使用 Unity 作为 IoC 的 asp.net MVC4 应用程序。我的控制器的构造函数接受一个存储库,而该存储库接受一个 UnitOfWork (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 请求快速发生时才会发生,这意味着快速。当请求以正常速度发生时,一切似乎都很好。就像应用程序需要时间来赶上一样。不知道我需要如何处理我的存储库中的并发检查,所以我不会错过更新。另外,我尝试将“MultipleActiveResultSets”设置为 true,但没有帮助。

4

1 回答 1

1

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

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

现在,如果这些操作是由并发请求执行的,您可能会收到以下信息:

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

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

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