使用 ADO.NET TransactionScope 与 NOLOCK 上的 ExecuteCommand 的高容量站点,直接读取未提交的内容?
-
06-07-2019 - |
题
只需阅读奥马尔在他的博客上发表的这篇有趣的文章 Linq to SQL使用未提交读取解决事务死锁和查询超时问题 最后,贾维德·哈桑(Javed Hasan)开始与他争论他对大容量地点上的诺洛克局势的解决方案。
这里,要解决的问题是,从sql意义上讲,我们需要使用带NOLOCK的Select语句或使用SET TRANSACTION LEVEL READ UNCOMMITTED,否则在数据库中的高容量行将被锁定并导致错误。Omar 使用的技术是 Linq2Sql,所以问题是我们如何在 C# 数据访问代码中实现这一目标,这样上述情况就不会发生?
基本上在这篇文章中,Omar 通过在现实世界的网站上工作和测试以及使用 SqlProfiler 等工具来得出他的解决方案,而 Javed Hasan 通过 MSDN 文档和 Scott Hanselman 的博客文章等得出他的解决方案。
奥马尔建议使用以下内容
using (var db = new DropthingsDataContext2())
{
db.Connection.Open();
db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
var user = db.aspnet_Users.First();
var pages = user.Pages.ToList();
}
而 Javed Hasan 建议
using (new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted }))
{
//Your db Operation
}
我很想知道你们在像 StatckOverflow 这样的高容量网站上针对这个特定问题做了什么,或者 Jeff 和他们的人在这方面做了什么?
编辑: :读完第一篇文章后,我想指出奥马尔文章中的一些内容。
- 他的方法确实遇到了连接问题,但他解决了,请参阅他的帖子。
- 更重要的是,他提到他尝试过使用 ADO.NET 事务方式,甚至尝试了 Scott Hanselman 在他的博客上写的内容,但它不适用于高容量网站,它会大大降低性能。Omar 表示,“System.Transactions 的开销很大。我从来没有能够在大容量网站上使用它而不使 CPU 达到 100% 且请求/秒降至 1/10。它是为企业应用程序而设计的,而不是为大容量网站而设计的。”
解决方案
首先,请避免未提交的读取,它们可能会导致很多问题。更好的方法是将数据库设置为 快照隔离. 这就是杰夫所做的.
杰夫基本上说:“ bla bla bla,是真实的,bla bla bla,数据库理论家,bla bla bla,不读取的不承认对于不需要数据一致性的真实生产应用程序很有用。”杰夫不是DBA,幸运的是,这里有很多DBA。
Omar 方法的问题在于,它可能会将“读未提交”隔离级别的连接泄漏到您的连接池中,这可能会对您的网站造成严重破坏。这意味着随机语句可以在未提交的读中执行。
Javed 方法会更好,因为在处置时 MS 有机会清理连接上的东西。
编辑 如果您在使用 Javed 的方法时遇到性能问题,您可以考虑滚动自己的事务管理器。
您可能想做的一些事情:
- 保存当前交易的堆栈
- 提交事务时确认您位于创建者线程上
- 在处置时将事务隔离重置为其之前的状态
- 如果事务未提交,则回滚处置。
- 支持嵌套回滚。
其他提示
我是Microsoft的SQL Server组中的工具团队的开发人员。许多应用程序对事务一致性不是非常敏感,特别是如果您编写的应用程序执行报告或偶尔会出现不一致的数据并不是世界末日。当然,如果您编写的财务应用程序或其他对数据不一致性容忍度很低的内容,您可能希望探索其他解决方案。
如果选择使用未提交的读取,我有使用C#中的扩展方法为博客提供了便利的解决方案。
{我的(糟糕的)声誉使我无法发表评论,所以我将此作为答案}
如果通过 System.Transactions 使用 IsolationLevel 并在事务块内创建新的 Linq 上下文,SQL Server 最终会尝试调用 DTC 来协调事务。这件事刚刚发生在我身上,而且是出乎我的意料。
关于.Net中的交易和DTC的(某种程度上令人惊讶的)副作用,本文件 .NET Framework 2.0中的System.Transactions介绍解释得非常好并且仍然完全有效(.Net4)。值得阅读。 (如果可以的话,我也会发表评论。)