在 LINQ to SQL 中使用 TransactionScope 改变隔离级别为 NOLOCK,是否会影响连接?

5

我正在测试使用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 可以返回脏读。 这些可能包括从技术上讲从未属于数据库的记录。 来源 - MSDN。 更多内容请参见这篇博客文章 - David Rushton
没错,这正是我想要执行只有某些查询的原因,而我可以用READ UNCOMMITTED隔离级别来处理脏读。问题是,使此成为LINQ to SQL甚至EF中的解决方案也会影响其他查询,这不是期望的行为。 - Huzaifa Tapal
这必须与连接池中实际连接有关,其生存时间介于[4分钟和7分40秒]之间(http://www2.sys-con.com/itsg/virtualcd/dotnet/archives/0112/smith/index.html)。 - Gert Arnold
2个回答

0

我们遇到了与此完全相同的问题。我们使用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");

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

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


0
你需要使用闭合符号来结束作用域。
ts.Complete()

查询后,返回前


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接