我有一个OData服务(使用实体框架的WCF数据服务)。
所有这项服务都是选择数据。 (没有写过。)
当我运行OData查询时,我偶尔会收到这样的错误:
事务(进程ID 95)在锁资源上与另一个进程发生死锁,并被选为死锁牺牲品。重新运行交易
select语句可以成为死锁受害者吗?或者实体框架试图锁定不应该锁定的东西吗?
如果它锁定在它不应该的位置,是否有办法告诉实体框架永远不会锁定? (对于这项服务,它始终是永久性的,只能是只读的。)
答案 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();
}