4

我们在使用 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/

4

3 回答 3

3

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

于 2012-11-14T16:40:25.983 回答
2

情况还是一样。EF 没有任何附加功能可以避免这种情况。所以你的解决方案可以是:

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

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

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

于 2012-01-19T10:20:55.280 回答