使用Linq to SQL的NOLOCK


Answers:


86

是的,所以这是我的博客中的条目:

NOLOCK提示与在“隔离级别”设置为“读取未提交”的事务中包装查询是基本相同的。这意味着查询不在乎是否正在将材料写入到要从其读取的行中-它会读取“脏”数据并将其作为结果集的一部分返回。

事实证明,您可以使用.NET 2.0中引入的旧System.Transactions命名空间来完成整个“读取未提交的”事务。这是一些示例代码:

using (var txn = new TransactionScope(
    TransactionScopeOption.Required, 
    new TransactionOptions
    {
        IsolationLevel = IsolationLevel.ReadUncommitted
    }
))
{
    // Your LINQ to SQL query goes here
}

因此,我正在创建一个新的TransactionScope对象,并告诉它使用未提交的隔离级别。现在,“ using”语句中的查询的行为就像其所有表都在读取带有NOLOCK提示的内容一样。

这是Google搜索“ linq sql nolock”的第一个结果:

InfoQ:使用LINQ to SQL和LINQ to Entities实现NOLOCK

Matt Hamilton-SQL和NOLOCK的LINQ提示:疯狂的道具!

斯科特·汉塞尔曼(Scott Hanselman)的《计算机禅-LINQ to SQL和LINQ to ...


6
如果我想完全正确,那么这些选项实际上都不在SQL本身中“发出NOLOCK”,而是使用事务的隔离设置。同样的事情,但从技术上讲不是问题的要问。
马特·汉密尔顿,

3
从您的博客中复制了文本,因此无需任何人单击链接即可获得答案。
Eric

2
@Matt:这就是重点!创建规范来源!参见:meta.stackexchange.com/questions/8724/…–
埃里克

7
在内容盗用方面必须同意Matt的意见。马特(Matt)花时间在他的博客上撰写帖子。现在,SOF越来越拥挤
安德鲁·哈里

4
您无法在博客上投票和否决答案,因此无法审查那里的质量。我认为通过归因将简短摘要复制到SO是正确的方法。
Kirk Woll

23

除了King的LinqPadMy Extensions之外

public static IQueryable<T> DumpNoLock<T>(this IQueryable<T> query)
{
    using (var txn = GetNewReadUncommittedScope())
    {
        return query.Dump();
    }   
}

public static System.Transactions.TransactionScope GetNewReadUncommittedScope()
{
    return new System.Transactions.TransactionScope(
        System.Transactions.TransactionScopeOption.RequiresNew,
        new System.Transactions.TransactionOptions
        {
            IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
        });
}
public static IQueryable<T> DumpNoLock<T>(this IQueryable<T> query, string description)
{
    using (var txn = GetNewReadUncommittedScope())
    {
        return query.Dump(description);
    }   
}

public static List<T> ToListNoLock<T>(this IQueryable<T> query)
{
    using (var txn = GetNewReadUncommittedScope())
    {
        return query.ToList();
    }   
}

public static U NoLock<T,U>(this IQueryable<T> query, Func<IQueryable<T>,U> expr)
{
    using (var txn = GetNewReadUncommittedScope())
    {
        return expr(query);
    }   
}

最后一种意味着您可以NOLOCK对未NoLock明确为其编写的任何评估查询执行“ a ”操作(ToListNoLock如上文所述)。因此,例如:

somequery.NoLock((x)=>x.Count()).Dump();

将使用评估查询NOLOCK

请注意,您必须确保正在评估查询。例如.NoLock((x)=>x.Distinct()).Count().Dump()不会做任何与有用的区别.Distinct().Count().Dump()


11

一种简单的方法可能是在您的DataContext类上运行命令

using (var dataContext = new DataContext())
{
  dataContext.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");

  // Your SQL query
}

也许嵌入国王之谜的答案很不错
Pierre

8

这是与LINQPAD一起使用的扩展方法

    public static IQueryable<T> Dump2<T>(this IQueryable<T> query)
{
    using (var txn = new System.Transactions.TransactionScope(TransactionScopeOption.RequiresNew, 
        new TransactionOptions
        {       
            IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
        }))
    {
        return query.Dump();
    }   
}

然后,您可以将其称为:

MyTable.Where(t => t.Title = "Blah").Dump2();

2

以我为例,实体框架5(基于@Soppus答案):

private FoobarEntities db = new FoobarEntities();
public FoobarController()
{
    db.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
}

1
谢谢,您的解决方案避免了“ COMException:事务管理器已禁用对远程/网络事务的支持。” 可能会附加在其他请求上。
Olivier de Rivoyre
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.