实体框架Upsert异步竞争条件。有更好的解决方法吗?

时间:2015-06-30 17:28:36

标签: sql-server asp.net-mvc entity-framework

针对我的MVC5 WebAPI控制器的帖子检查数据库中是否存在某个项目,如果该项目不存在则添加该项目。如果确实存在,则更新它。它不使用主键,标识字段,而是使用名为Name的字段。

场景是这样的。 我有两个JSON客户端试图添加(发布)记录。 该应用程序需要一些时间来进行预热。 应用程序启动后,第一个Post命中并且其第一个异步查询检查是否存在。 当等待时,第二个帖子命中并检查是否存在,找不到记录,然后插入它。 然后第一个Post从它的await返回,找不到记录并插入它。

首先,我在Name字段上放置了一个唯一索引,因此在上述条件下会出错。 然后我的第一个帖子会因重复索引违规而出错,这很好。 然后我改变了我的EF调用以避免异步,认为我不会放弃(通过等待)到第二个帖子,我的第一个帖子只是在执行读取然后插入前进。这似乎允许两个帖子完成而没有任何重复的插入错误。注意:第二篇文章现在进行更新,而不是插入。

我认为这并没有消除多线程环境中索引冲突错误的可能性。 也许C#锁可以工作,但不能扩展到多个服务器。 从其他SO线程,我读到EF Upserts(AddOrUpdate)不是线程安全的,例如不是真正的SQL Upserts。

可能很多毫无防备的程序员都有这些类型的错误,像我一样,他们只是开始使用异步/等待所有东西。

是否有更强大的解决方法(没有存储过程)?

1 个答案:

答案 0 :(得分:0)

有两种方法可以解决这个问题。

  1. 停止对数据库的第二次调用
  2. 将支票(如果存在)和插入物放入交易中。然后第二个调用将等到第一个完成,并且它将看到数据已经存在于数据库中。

    1. 让第二次更新发生
    2. 如果没有产生任何问题,请进行第二次更新。

      如果在1000次调用中发生此问题,那么使用一次额外的数据库更新而不是1000次数据库锁定可能会更好。