与并行插入多行时的实体框架死锁

时间:2011-12-29 11:46:22

标签: entity-framework-4 database-deadlocks

我们在使用EF并行插入多个实体时遇到问题。许多进程调用WCF操作以在每次调用中生成具有不同分布式事务的实体。正如我们在sql server profiler中看到的那样,它会生成以下sql:

(@0 int,@1 nvarchar(32),@2 datetime2(7),@3 nvarchar(64),@4 int,@5 int,@6 bit)
insert [dbo].[CommandRequests](
   [CommandId]
 , [DeviceId]
 , [StartDateTime]
 , [EndDateTime]
 , [Parameters]
 , [Caller]
 , [Result]
 , [Priority]
 , [Timeout]
 , [ParentRequestId]
 , [IsSuccessful]
 , [Host])
  values (@0, @1, @2, null, null, @3, null, @4, @5, null, @6, null)

  select [CommandRequestId]
  from [dbo].[CommandRequests]
  where @@ROWCOUNT > 0 and [CommandRequestId] = scope_identity()   

所以EF给我们一个插入,然后选择。因为它是并行完成的,所以很多都会被死锁中止。

我们使用的是EF 4.0,而不是4.1或4.2。

知道如何解决这个问题吗?我见过这个,但它已经很老了: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/4f634d8f-1281-430b-b664-ec7ca413b387/

3 个答案:

答案 0 :(得分:2)

情况仍然相同。 EF没有任何其他功能可以避免这种情况。所以你的解决方案可以是:

  • 服务中的手动同步,以便一次只能有一个呼叫插入记录。这非常难看,它将极大地影响吞吐量,但是对于这个单一操作实现简单的悲观锁定是非常容易的解决方案,因此它取决于您正在构建的应用程序的类型。
  • 最后看到的选择是使用自动生成的ID引起的。需要通知EF有关此ID的信息。您无法仅在插入时关闭此功能。您可以做的是不在数据库中使用自动生成的ID并在您的应用程序中处理Id生成。您将在DB / EF之外移动Id生成,您将完全控制其同步。之后,您再也不会看到此选择(您还必须将Id属性的StoreGeneratedPattern设置为None)。例如,您可以实现自定义HiLo Id algorithm

答案 1 :(得分:2)

最后问题在于可序列化事务中的死锁,与id的创建无关。

我在这里解释一下这个问题: http://pablocastilla.wordpress.com/2012/01/19/deadlocks-in-serializable-transactions-with-sql-server/

答案 2 :(得分:1)

我认为原因是CommandRequestId不是主键。如果将其设置为主键,则不会出现死锁。我遇到了同样的问题,当我将Identity列设置为主键时,它工作正常。