1

似乎错误“分布式事务已完成。在 NULL 事务的新事务中登记此会话”是一个普遍存在的问题,有许多讨论和不同的原因,但环顾四周后,我仍然无法确定可能是什么原因就我而言。我正在使用 LINQ-to-SQL DataContext 派生类来查询和更新数据库,但我们所做的大约一半更新分为直接 SQL 更新和通过插入、更新和删除的部分方法中的另一个 API 执行的更新数据上下文。当我们检测到 SQL 和第三方更新都将发生时,我们使用“TransactionScopeOption.Required”选项创建一个新的 TransactionScope 对象,然后检索环境事务并将第三方 API 加入同一个分布式事务中。

在大多数情况下,这似乎一直在相对可靠地工作。但是有时会发生罕见且难以重现的错误。当由于 DataContext 上的部分方法期间的某些验证失败而在 SubmitChanges 期间发生预期的(用户)错误时,我们的代码将在不调用 Complete 的情况下处理 TransactionScope 并将错误报告给用户。如果再次尝试相同的事务,有时它会起作用,但有时我们会收到错误报告意外的 DTC 错误。

真正奇怪的部分是,如果我执行 Debug.WriteLine 来检查 System.Transactions.Transaction.Current 的状态,那么我将无法再报告错误。如果我更改代码以将相同的信息报告到文本文件而不是调试流,我可以轻松地重现错误。这让我怀疑发生了一些奇怪的线程同步问题。

在寻找答案时,我偶然发现了一个主题,该主题导致我尝试使用 RequiresNew 而不是 Required 作为 TransactionScopeOption。但这在类似情况下导致了不同的错误:“ExecuteReader 需要一个打开且可用的连接。连接的当前状态是打开。”

我已经确认(通过文件的调试输出)当我在 DataContext 上调用 Refresh 时,环境事务是 Nothing,然后在框架的 Refresh 实现中的某个地方是两种情况下都会发生错误的地方。我难住了。为什么它认为我正在尝试参与交易?

编辑:这个谜题越来越令人困惑。我再次尝试了同样的事情(仍然使用 RequiresNew)并得到“Internal .Net Framework Data Provider Error 12”。是否有关于此错误 12 的任何信息可以提供线索,了解这里的幕后情况?

4

1 回答 1

0

Internal .Net Framework Data Provider Error 12是一个很好的线索,表明正在发生对非线程安全数据框架的多线程访问。实际上,我能够确认事件在另一个线程上引发DataContext.Refresh的同时在一个线程上执行System.Transactions.Transaction.TransactionCompleted,并且我有事件处理程序代码在其中取消登记事务的其他成员(第三方 API)。显然试图同时这样做会引起一些我不完全理解的混淆,但是通过确保两个线程不能同时与连接/事务交互可以很容易地避免这种情况。我建议使用SyncLock(VB.NET)、lock(C#) 或Threading.Monitor.EnterandThreading.Monitor.Exit来帮助确保多个线程避免同时访问数据提供者。

于 2012-11-15T16:33:36.280 回答