只读声明中的实体框架死锁受害者

时间:2012-03-23 16:40:39

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

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

所有这项服务都是选择数据。 (没有写过。)

当我运行OData查询时,我偶尔会收到这样的错误:

  

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

select语句可以成为死锁受害者吗?或者实体框架试图锁定不应该锁定的东西吗?

如果它锁定在它不应该的位置,是否有办法告诉实体框架永远不会锁定? (对于这项服务,它始终是永久性的,只能是只读的。)

2 个答案:

答案 0 :(得分:11)

不要只使用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

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

答案 1 :(得分:1)

您没有提到OData服务背后的数据库,因此这可能无关紧要。在SQL Server中,您可以使用SELECT语句WITH nolock来阻止select锁定表。这种情况的存在告诉我SELECTS肯定是锁定问题的候选者。

不幸的是,在EF中,无法在查询中指定WITH nolock。我能找到的最接近的是将您的连接包装在一个事务中并设置isolation level to read uncommited(如我在评论中链接的问题的答案中所示)。

以下是相关问题答案中的示例代码,说明如何执行此操作:

//declare the transaction options
var transactionOptions = new System.Transactions.TransactionOptions();
//set it to read uncommited
transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
//create the transaction scope, passing our options in
using (var transactionScope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
{
    //declare our context
    using (var context = new MyEntityConnection())
    {
        //any reads we do here will also read uncomitted data
        //...
        //...
    }
    //don't forget to complete the transaction scope
    transactionScope.Complete();
}