【问题标题】:Snapshot isolation in SQL / code blocking readsSQL / 代码阻塞读取中的快照隔离
【发布时间】:2014-02-15 07:55:17
【问题描述】:

我怀疑我不完全了解正在发生的事情或发生了什么奇怪的事情。 (我猜第一种情况更可能。)

大局:

  • 我正在尝试让 Web 服务异步执行某些操作,因为它们可能很耗时,而且我不希望客户端等待操作完成(只需不时查询结果以查看操作完成)。
  • 异步代码包含在事务中 - 万一出现问题,我希望能够回滚任何更改。
  • 不幸的是,异步代码的最后一步是调用查询同一数据库的不同服务。
  • 尽管将整个事物包装在 Snapshot 事务中,但最后一步还是失败了,因为服务无法从数据库中读取数据。
  • 就此而言,虽然正在进行异步操作,但我也无法从数据库中执行简单的 SELECT 语句。

这是我目前用来测试事务的代码示例(首先使用 Entity Framework 5 模型):

        using (var transaction = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.RequiresNew, new System.Transactions.TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.Snapshot }))
        {
            var db = new DataModelContainer();
            Log test = new Log();
            test.Message = "TEST";
            test.Date = DateTime.UtcNow;
            test.Details = "asd";
            test.Type = "test";
            test.StackTrace = "asd";
            db.LogSet.Add(test);
            db.SaveChanges();
            using (var suppressed = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Suppress))
            {
                var newDb = new DataModelContainer();
                var log = newDb.LogSet.ToArray();  //deadlock here... WHY?
            }
            test = db.LogSet.Where(l => l.Message == "TEST").Single();
            db.LogSet.Remove(test);
            db.SaveChanges();
            transaction.Complete();
        }

代码在数据库中创建了一个简单的日志条目(是的,我现在正在玩,所以这些值是垃圾)。我已将 SQL 数据库设置为允许快照隔离,据我所知,仍应允许读取(在此代码中通过使用新的抑制事务和新的DataModelContainer 对这些进行测试)。但是,我无法在被抑制的事务或 SQL Management Studio 中查询 LogSet - 整个表被锁定!

那么……为什么?如果事务范围是这样定义的,为什么会被锁定?我也尝试过其他隔离级别(如ReadUncommited),但仍然无法查询该表。

有人可以解释一下这种行为吗?

【问题讨论】:

  • 您的数据库中是否启用了快照隔离? "在事务中使用之前,必须通过设置 ALLOW_SNAPSHOT_ISOLATION ON 数据库选项来启用快照隔离"
  • @Moho 是的。 我已将 SQL 数据库设置为允许快照隔离。无论如何,当使用其他隔离模式(比Serializable 限制更少)时,问题仍然存在,例如ReadUncommited,而且这个甚至不需要在 SQL 服务器上启用快照隔离!

标签: c# sql-server entity-framework transactionscope isolation-level


【解决方案1】:

在 SSMS 中,将您当前的隔离级别设置为 SNAPSHOT 并查看是否可以解决您的问题 - 它可能已设置为 READ COMMITTED,因此仍会因未决更新而阻塞。

更新:

您可以通过更改以下选项允许READ COMMITTED 访问数据库范围内的版本化行(并避免必须不断将当前隔离级别设置为SNAPSHOT):

ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON

【讨论】:

  • 感觉好像完全没有使用C#中的隔离级别设置。快照隔离只是一个不应发生锁定的极端示例,但问题也与其他隔离级别有关。检查更新的 C# 代码——此时我不需要使用 SSMS 来执行测试。此外,设置READ_COMMITTED_SNAPSHOT 是一个部分解决方案 - 如上所述,它不能解释为什么没有正确设置事务隔离(如果设置了的话)。
  • 您的其他会话的隔离级别是什么,正如我在解决方案中所说的那样。如果您设置为READ COMMITTED - 它会锁定,直到您提交更改。这就是 READ_COMMITTED_SNAPSHOT 设置的全部目的 - 防止在等待 SNAPSHOT 提交时阻塞
  • 啊,我想我明白问题所在了。我的印象是我需要显式打开一个事务(例如,在执行简单的 SELECT SSMS 查询时)。
猜你喜欢
  • 2011-02-14
  • 1970-01-01
  • 1970-01-01
  • 2019-12-27
  • 2019-07-02
  • 2010-11-10
  • 2014-02-20
  • 2014-01-03
  • 1970-01-01
相关资源
最近更新 更多