将TransactionScope与read uncommitted一起使用 - 是否必须在SQL中使用(nolock)?

时间:2013-09-30 09:32:33

标签: sql-server-2008 c#-4.0 nhibernate transactions fluent-nhibernate

我正在使用FluentNHibernate,我有一个记录列表,映射到SQL Server 2008视图。脏的读取对我来说没关系,不是锁定表是一个优先事项。

视图中的SQL查询,没有任何with(nolock),但是,我使用以下方法......

using (var txScope = new TransactionScope(TransactionScopeOption.Suppress, new TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
   ... The reading of records from the view is done here, through Fluent NHibernate...
}

将应用程序层的隔离级别设置为未提交读取,将(nolock)应用于在该上下文中生成的查询吗?

2 个答案:

答案 0 :(得分:12)

简答:否

答案很长:

仅定义TransactionScope并未定义将在事务中调用任何读取或写入。

要在事务中运行某些内容,您仍然需要打开并提交事务!

TransactionOptionsTimeout的TransactionScope的IsolationLevel只为范围内创建的任何事务定义默认值,而不显式设置这些选项。实际上,TransactionScope确实创建了一个事务,但如果没有打开新事务,它将不会处于活动状态。在内部,这将做一些复杂的事情,克隆事务等...所以让我们忽略这个......

如果没有事务,您无法定义隔离级别,任何select语句都将与IsolationLevel.ReadCommitted一起运行,因为这是SQL Server的默认值。

您还可以查询session.Transaction.IsActive以查看会话当前是否处于活动状态!

让我们看看下面的代码,我提出了一些评论,以使其更清晰

using (var scope = new TransactionScope(TransactionScopeOption.Required,
                    new TransactionOptions()
                    {
                        IsolationLevel = IsolationLevel.ReadUncommitted
                    }))
{

    using (var session = sessionFactory.OpenSession())
    {
        // outside any transaction...
        var x = session.Transaction.IsActive; // false;

        // read will be done with SQL Server default (ReadCommited)
        var pp = session.Query<Page>().Where(p => p.Photos.Count() > 1).ToList();

        using (var transaction = session.BeginTransaction())
        {
            // will use ReadUncommitted according to the scope
            var y = session.Transaction.IsActive; // true;

            var p1 = session.Get<Page>(1);

            transaction.Commit();
        }
        using (var transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
        {
            // will use ReadCommitted according to the transaction initialization
            var y = session.Transaction.IsActive; // true;

            var p1 = session.Get<Page>(1);

            transaction.Commit();
        }

        scope.Complete();
    }
}

您还可以使用SQL Server Profiler观察SQL Server如何对这些设置做出反应。

只需创建一个新的Trace并注意Audit Login事件,事件的文本将包含隔离级别,您可以看到每次创建事务时它实际上都会执行Audit Login ,例如

 set transaction isolation level read uncommitted

-

请纠正我,如果这些信息可能有误,我只是自己想出来这样可能会有一些失败的原因;)

答案 1 :(得分:0)

我不确定原因,但是TransactionScope代码对我不起作用。

我使用了这段代码。在下面开始新会话可确保您已经没有现有交易。 (当然还有其他方法可以做到)

        using (var session = _session.SessionFactory.OpenSession())
        using (var txn = session.BeginTransaction(IsolationLevel.ReadUncommitted))
        {
            // bunch of select statements.
        }

在NHibernate Profiler中我可以看到:

begin transaction with isolation level ReadUncommitted