【问题标题】:Entity Framework Dead Lock Victim on Read Only Statements实体框架死锁受害者只读语句
【发布时间】:2012-03-24 01:53:18
【问题描述】:

我有一个 OData 服务(使用实体框架的 WCF 数据服务)。

此服务所做的只是选择数据。 (从来没有写过。)

当我运行 OData 查询时,我偶尔会遇到如下错误:

事务(进程 ID 95)在锁定资源上与另一个进程死锁,并已被选为死锁牺牲品。重新运行事务

select 语句会成为死锁的牺牲品吗?还是实体框架试图锁定它不应该锁定的东西?

如果它在不应该锁定的地方锁定,有没有办法告诉实体框架从不锁定? (对于此服务,它始终是只读的。)

【问题讨论】:

标签: c# entity-framework entity-framework-4 wcf-data-services odata


【解决方案1】:

不要只使用 ReadUncommitted 或 NOLOCK。这些将 a) 轻松返回不一致的结果,b) 由于“数据移动”而导致虚假错误。不要!

一个更好的主意是使用以下 SQL 启用快照隔离:

ALTER DATABASE [DB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
ALTER DATABASE [DB] SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE [DB] SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE [DB] SET MULTI_USER

这将导致读取事务不占用任何锁并且不会被现有锁阻塞。这可能会解决您的问题。

【讨论】:

  • 锁是否仅受读取影响,或者说每分钟对单个表进行 1k 插入或更新也会受此影响?
  • 快照模型下的读取不会阻塞。写入可以阻塞。但是写入不会阻塞读取。您可以删除包含 10 亿行的整个表,而读者不会注意到,仍然会看到旧数据。
  • EF 数据库优先的 Contexts 程序员没有能力修改目标数据库怎么办?例如,我针对另一个供应商的数据库开发了一个只读服务。在这种情况下,首选的解决方案是什么?
  • 理想情况下,您应该让他们启用此功能。如果没有,您可以使用其他隔离级别获得不错的结果。使用TransactionScope 控制级别。此时您别无选择,只能了解各个级别采用了哪些锁。唉,没有硬性规定。 (对于启用 SI 的读取事务,确实有一个快速规则:始终使用 SI。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多