【问题标题】:Does changing isolation level using TransactionScope in LINQ to SQL for NOLOCK impact the connection?在 LINQ to SQL 中为 NOLOCK 使用 TransactionScope 更改隔离级别会影响连接吗?
【发布时间】:2016-07-09 13:47:14
【问题描述】:

我正在测试使用 TransactionScope 以及将隔离级别设置为 ReadUncommitted 的选项来执行特定查询。然而,我看到的是,由于在连接上设置了隔离级别,当连接被重用于其他查询时,隔离级别仍然是 ReadUncommitted 而不是重置为默认的 ReadCommitted。

根据许多建议,我将新的 NoLock 方法抽象为如下扩展:

public static class QueryableExtensions
{
    static TransactionScope CreateNoLockTransaction()
    {
        return new TransactionScope(TransactionScopeOption.Required, new TransactionOptions
        {
            IsolationLevel = IsolationLevel.ReadUncommitted
        });
    }

    public static T[] ToNoLockArray<T>(this IEnumerable<T> query)
    {
        using (var ts = CreateNoLockTransaction())
        {
            return query.ToArray();
        }
    }

    public static List<T> ToNoLockList<T>(this IEnumerable<T> query)
    {
        using (var ts = CreateNoLockTransaction())
        {
            return query.ToList();
        }
    }

    public static int NoLockCount<T>(this IEnumerable<T> query)
    {
        using (var ts = CreateNoLockTransaction())
        {
            return query.Count();
        }
    }
}

然后我想验证我在事务范围内和不在事务范围内运行的各种查询的隔离级别。为此,我开始使用查询的上下文执行以下查询:

db.ExecuteQuery<int>("select cast(transaction_isolation_level as int) from sys.dm_exec_sessions where session_id = @@SPID").FirstOrDefault();

在执行 NoLock 扩展方法之前运行上述,返回隔离级别为 2。在运行 NoLock 扩展方法并检查事务范围外查询的隔离级别后,返回 1。

这是否意味着当使用 TransactionScope 更改隔离级别时,受影响的连接在重新用于其他查询和数据上下文时,会继续使用 ReadUncommitted 隔离级别?这是否会破坏使用事务临时更改特定查询的隔离级别的目的,因为它会影响之后的所有查询?

【问题讨论】:

  • 离题 - 我相信你知道READ UNCOMMITTED 可以返回脏读。这些可以包括技术上从未属于数据库的记录。 Source - MSDN。更多信息请见this blog entry
  • 对,这正是我只想执行某些查询的原因,这些查询我可以用 READ UNCOMMITTED 隔离级别考虑脏读。问题是在 LINQ to SQL 中实现这一点的解决方案,甚至可能 EF 也会影响其他查询,这是不希望的行为。
  • 这一定与位于4 minutes and 7 minutes, 40 seconds之间的连接池中的真实连接有关。

标签: sql-server linq-to-sql transactions isolation-level transaction-isolation


【解决方案1】:

你需要关闭作用域

ts.Complete()

查询之后,返回之前

【讨论】:

    【解决方案2】:

    我们遇到了与此完全相同的问题。我们使用 LINQ to SQL 并使用 TransactionScope 对象会导致整个 sql spid 被读取而未提交。

    这是我能找到的唯一方法,只读取未提交的当前查询:

    dbContext.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
    
    var Data = query.ToList();
    
    dbContext.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ COMMITTED");
    

    这显然不是一个好方法,因为在 sql 进程中执行的其他查询可能会在打开的几毫秒内受到影响,并且它会生成对 DB 服务的两个额外调用。

    如果有办法让 LINQ 在 select 语句中生成事务隔离级别,那就更好了。

    【讨论】:

      猜你喜欢
      • 2011-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多