我一直在这里和其他地方寻找一段时间,但无法找到一个很好的答案为什么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个客户死锁).上面的结果只是另一种僵局,实际上并没有解决我的问题.
所以我知道我能做的是:
>避免使用相同连接的嵌套用法
>增加服务器上的连接池大小
但我的问题是:
>这在不久的将来是不可能的,因为许多代码行重新分解并且它将与架构冲突(甚至没有开始评论这是好还是坏)
>即使这当然会起作用,这就是我所谓的“对症治疗” – 因为我不知道应用程序会增长多少以及这是否是未来的可靠解决方案(然后我可能最终会一个更糟糕的情况,更多的用户受到影响)
我的想法是:
> NoLock是否真的不可能(对于没有启动事务的每个语句)?
>如果1为真 – 它真的是真的没有其他人得到这个问题并在一般的linq中解决它到sql修改?
>如果2为真 – 为什么这对其他人来说不是问题?
>还有其他解决方法我可能没看过吗?
>使用相同的连接(嵌套)多次如此糟糕的做法,没有人有这个问题?
解决方法:
1:LINQ-to-SQL确实不允许你指示像NOLOCK这样的提示;但是,可以编写自己的TSQL,并使用ExecuteQuery< T>等等
2:坦率地说,以优雅的方式解决会非常复杂;并且很有可能你会不恰当地使用它.例如,在“死锁”场景中,我会下注实际上你应该使用UPDLOCK(在第一次读取期间),以确保第一次读取采用写锁定;这可以防止后来的第二个查询获得读锁定,因此通常会阻塞而不是死锁
3:使用连接不一定是一个大问题(尽管注意新的Context()通常不会共享连接;要共享连接,您将使用新的Context(连接)).如果看到这个问题,有三种可能的解决方案(如果我们排除“使用带有提示支持的ORM”):
>使用显式事务(不必是TransactionScope – 它可以是连接级事务)来指定隔离级别
>使用提示编写自己的TSQL
>使用连接级隔离级别(注意我作为注释添加的警告)
IIRC还有一种方法可以对数据上下文进行子类化,并覆盖一些事务创建代码,以控制它在内部创建的事务的隔离级别.