LINQ-To-SQL NOLOCK(不是ReadUncommitted)

时间:2011-12-13 10:53:39

标签: c# linq-to-sql transactions nolock

我一直在这里和其他地方寻找一段时间,并且无法找到一个很好的答案为什么Linq-TO-SQL与NOLOCK不可能..

每次我搜索如何将with(NOLOCK)提示应用于Linq-To-SQL上下文(应用于1 sql语句)时,人们经常回答强制事务(TransactionScope),并将IsolationLevel设置为ReadUncommitted。好吧 - 他们很少告诉这导致连接打开一个事务(我也读过某个地方必须确保手动关闭)。

在我的应用程序中按原样使用ReadUncommitted,实际上并不是那么好。现在我已经在彼此之间使用了相同连接的上下文语句。像:

using( var ctx1 = new Context()) {
    ... some code here ...
    using( var ctx2 = new Context()) {
        ... some code here ...
        using( var ctx3 = new Context()) {
            ... some code here ...
        }
        ... some code here ...
    }
    ... some code here ...
}

总执行时间为1秒且同时有多个用户,更改隔离级别将导致上下文等待彼此释放连接,因为正在使用连接池中的所有连接。

因此,改变为“nolock”的原因之一是避免死锁(现在我们每天有1个客户死锁)。上面的结果只是另一种僵局,实际上并没有解决我的问题。

所以我知道我能做的是:

  1. 避免使用相同连接的嵌套用法
  2. 增加服务器上的连接池大小
  3. 但我的问题是:

    1. 由于许多代码行重新分解并且它会与架构冲突(甚至没有开始评论这是好还是坏),这在不久的将来是不可能的。
    2. 即使这当然会起作用,这就是我所说的“对症治疗” - 因为我不知道应用程序会增长多少以及这是否是未来的可靠解决方案(然后我可能会结束)更糟糕的情况,更多的用户受到影响)
    3. 我的想法是:

      1. NoLock是否真的可以(对于没有启动事务的每个语句)?
      2. 如果1是真的 - 真的可以真的没有其他人遇到这个问题并在一般的linq中解决它来修改sql吗?
      3. 如果2为真 - 为什么这对其他人来说不是问题?
        1. 是否有其他解决方法我可能没看过?
        2. 使用相同的连接(嵌套)多次这么糟糕的做法,没有人有这个问题?

1 个答案:

答案 0 :(得分:2)

1:LINQ-to-SQL确实不允许你指出像NOLOCK这样的提示;但 可以编写自己的TSQL,并使用ExecuteQuery<T>

2:坦率地说,以优雅的方式解决会非常复杂;并且很有可能你会不恰当地使用它。例如,在“死锁”场景中,我会下注实际上你应该使用UPDLOCK(在第一次阅读期间),以确保第一次读取采用写入锁;这可以防止后来的第二个查询获得读取锁,因此通常会阻塞而不是死锁

3:使用连接不一定是一个大问题(虽然请注意new Context() 不会通常共享连接;要共享连接,您将使用{{1} })。如果看到这个问题,有三种可能的解决方案(如果我们排除“使用带有提示支持的ORM”):

  • 使用显式事务( new Context(connection) - 它可以是连接级别事务)来指定隔离级别
  • 使用提示编写您自己的TSQL
  • 使用连接级隔离级别(注意我作为注释添加的警告)
IIRC还有一种方法可以将数据上下文和TransactionScope一些事务创建代码子类化,以控制它在内部创建的事务的隔离级别。