Entity framework 4 并行插入多行时实体框架死锁
我们在并行插入几个实体时遇到问题。WCF操作由许多进程调用,以在每次调用中生成具有不同分布式事务的实体。正如我们在sql server探查器中看到的,它生成以下sql:Entity framework 4 并行插入多行时实体框架死锁,entity-framework-4,database-deadlocks,Entity Framework 4,Database Deadlocks,我们在并行插入几个实体时遇到问题。WCF操作由许多进程调用,以在每次调用中生成具有不同分布式事务的实体。正如我们在sql server探查器中看到的,它生成以下sql: (@0 int,@1 nvarchar(32),@2 datetime2(7),@3 nvarchar(64),@4 int,@5 int,@6 bit) insert [dbo].[CommandRequests]( [CommandId] , [DeviceId] , [StartDateTime] , [End
(@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给我们一个插入,然后给我们一个选择。因为它是并行完成的,所以它们中的许多被死锁中止
我们使用的是EF4.0,而不是4.1或4.2
你知道怎么解决这个问题吗?我见过这个,但它很古老:
情况还是一样。EF没有任何其他功能来避免这种情况。因此,您的解决方案可以是:
- 服务中的手动同步,以便一次只能插入一个呼叫记录。这是非常难看的,它将极大地影响吞吐量,但只为这一个操作实现简单的悲观锁定是非常容易的解决方案,所以它取决于您正在构建的应用程序的类型
- 您在末尾看到的选择是由使用自动生成的ID引起的。需要将此ID告知EF。您不能仅在插入时关闭此功能。您可以不在数据库中使用自动生成的Id,而是在应用程序中处理Id生成。您将把Id生成移到DB/EF之外,并且您将完全控制其同步。此后,您将再也看不到此选择(您还必须将Id属性的
设置为StoreGeneratedPattern
)。例如,您可以实现自定义None
我认为原因是CommandRequestId不是主键。如果您将其设置为主键,则不会得到死锁。我也遇到了同样的问题,当我将Identity列设置为主键时,效果很好。我们正在考虑将select查询更改为:select scope_Identity()作为[CommandRequestId],其中@@ROWCOUNT>0您认为如何?该查询是由EF自动生成的。您想如何更改它?您可以使用函数在模型中更改它,我们已经这样做了,并且它可以工作。您的意思是将存储过程映射到insert操作?不,这是类似的,但是您用模型的xml编写查询。插入[dbo]。[CommandRequests]([CommandId]…)值(…)选择范围_identity()作为[CommandRequestId],其中@@ROWCOUNT>0