使用SqlTransaction和IsolationLevel进行冗长的读操作?

Bra*_*ith 8 c# sql-server ado.net transactions isolation-level

我正在执行几个长时间运行的SQL查询作为报告模块的一部分.这些查询是在运行时动态构造的.根据用户的输入,它们可以是单个或多个语句,具有一个或多个参数并在一个或多个数据库表上运行 - 换句话说,它们的形式不容易预料到.

目前,我只是在普通的情况下执行这些陈述SqlConnection,即

using (SqlConnection cn = new SqlConnection(ConnectionString)) {
    cn.Open();
    // command 1
    // command 2
    // ...
    // command N
}
Run Code Online (Sandbox Code Playgroud)

因为这些查询(实际上是查询批处理)可能需要一段时间才能执行,所以我担心会阻塞其他用户的读/写表.如果这些报告的数据在批处理执行期间发生变化,则不会出现问题.报表查询永远不应优先于这些表上的其他操作,也不应锁定它们.

对于涉及修改数据的大多数长时间运行/多语句操作,我会使用事务.这里的区别在于这些报告查询不会修改任何数据.我是否可以正确地将这些报告查询包装起来SqlTransaction以控制它们的隔离级别?

即:

using (SqlConnection cn = new SqlConnection(ConnectionString)) {
    cn.Open();

    using (SqlTransaction tr = cn.BeginTransaction(IsolationLevel.ReadUncommitted)) {
        // command 1
        // command 2
        // ...
        // command N

        tr.Commit();
    }
}
Run Code Online (Sandbox Code Playgroud)

这会实现我想要的结果吗?提交事务是否正确,即使没有修改数据?还有另一种方法吗?

Mar*_*ell 5

另一种方法可能是针对连接发布:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Run Code Online (Sandbox Code Playgroud)

它实现了相同的意图,而不会弄乱交易.或者您可以WITH(NOLOCK)在查询中使用表上的提示,这样做的好处就是根本不更改连接.

重要的是,请注意(异常):但是它会被更改(事务,事务范围,显式SET等),在从池中获取隔离级别时,不会在使用相同的基础连接之间重置隔离级别.这意味着如果您的代码更改了隔离级别(直接或间接),那么您的代码都不知道新连接的隔离级别是什么:

using(var conn = new SqlConnection(connectionString)) {
    conn.Open();
    // isolation level here could be **ANYTHING**; it could be the default
    // if it is a brand new connection, or could be whatever the last
    // connection was when it finished
}
Run Code Online (Sandbox Code Playgroud)

这让人WITH(NOLOCK)很有诱惑力.