【问题标题】:Concurrent insert in SQL Server 2012SQL Server 2012 中的并发插入
【发布时间】:2020-05-26 13:16:02
【问题描述】:

我在 ASP.NET 中编写了一个使用 Entity Framework 6 的 api。

这里是代码

cr = context.Responses.FirstOrDefault(s => s.RegistrationId ==registrationId);

if (cr == null)
{
    cr = new Responses()
                {
                    Answer = answer,
                    RegistrationId = registrationId,
                    CreationTime = DateTime.Now
                     };
    context.Responses.Add(cr);
}
else
{
    cr.Answer = answer;
}
context.SaveChanges();

这是我在数据库中的结果

但是在进行数据库插入时,它会以相同的创建时间两次插入相同的数据,这种情况经常发生。为什么会这样?避免这些重复插入的最佳方法是什么?

【问题讨论】:

  • 也许 UI(或 BL)正在发送两个同时运行的添加消息?您是否考虑过使用 lock(..) 语句?
  • @LongChalk 有机会从 UI 中同时调用它。我怎么能阻止它?你能帮我提供一些锁的样本吗?
  • 在 (Answer , RegistrationId) 上放置一个唯一的复合索引更简单(并且使用的资源少得多)。这几乎就是你想要的

标签: asp.net sql-server entity-framework api concurrency


【解决方案1】:

首先应该是 cr = context.Responses.FirstOrDefault(s => s.RegistrationId == registrationId );

此错误可能源自 UI。假设您正在按表单填写回复,并且有人按了两次提交,那么您将在 db 中有两行代表相同的回复。解决此问题的正确方法是让表单(通过 javascript 等)生成 guid,并在单击后立即禁用提交按钮。另一种方法是在数据库中声明结果列的组合是唯一的,因此定义上不能存在两个“相同”的行。

【讨论】:

  • 第一件事——我的错。我更新了第二个问题-我确信没有更多的代码添加到同一个实体。我有一个 guid 的主键。我没有在上面显示。我可以更新代码以从 sql 获得创建时间。但这仍然不能解决问题吗?
  • 实际上会。如果您意识到“响应”实际上是一个答案和一个 registrationId(而不是 guidId 或 createDatetime 或您可能持有的任何其他垃圾),那么您很快就会意识到这两者形成了一个唯一的复合索引。顺便说一句 - 将 guid 作为主键是非常糟糕的做法。使用 id identity(1,1) 作为 PK,另外还有一个 guidId。这样您就可以获得前所未有的安全性,而不会出现数据库碎片。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多