c# - TransactionScope 在某些机器上自动升级到 MSDTC?

标签 c# .net transactions transactionscope msdtc

在我们的项目中,我们使用 TransactionScope 来确保我们的数据访问层在事务中执行它的操作。我们的目标是不要求在最终用户的计算机上启用 MSDTC 服务。

问题是,在我们一半的开发人员机器上,我们可以在禁用 MSDTC 的情况下运行。另一半必须启用它,否则他们会收到“[SERVER] 上的 MSDTC 不可用”错误消息。

这真的让我摸不着头脑,让我认真考虑回滚到基于 ADO.NET 事务对象的类似 TransactionScope 的家庭解决方案。这看起来很疯狂 - 在我们开发人员的 的一半上工作(并且不会升级)的相同代码在其他开发人员的 上升级。

我希望对 Trace why a transaction is escalated to DTC 有更好的回答,但不幸的是它没有。

这是一个会导致问题的示例代码,在尝试升级的机器上,它尝试在第二个 connection.Open() 上升级(是的,当时没有其他连接打开。)

using (TransactionScope transactionScope = new TransactionScope() {
   using (SqlConnection connection = new SqlConnection(_ConStr)) {
      using (SqlCommand command = connection.CreateCommand()) {
         // prep the command
         connection.Open();
         using (SqlDataReader reader = command.ExecuteReader()) {
            // use the reader
            connection.Close();
         }
      }
   }

   // Do other stuff here that may or may not involve enlisting 
   // in the ambient transaction

   using (SqlConnection connection = new SqlConnection(_ConStr)) {
      using (SqlCommand command = connection.CreateCommand()) {
         // prep the command
         connection.Open();  // Throws "MSDTC on [SERVER] is unavailable" on some...

         // gets here on only half of the developer machines.
      }
      connection.Close();
   }

   transactionScope.Complete();
}

我们真的深入挖掘并试图解决这个问题。以下是有关它工作的机器的一些信息:
  • 开发 1:Windows 7 x64 SQL2008
  • 开发 2:Windows 7 x86 SQL2008
  • 开发 3:Windows 7 x64 SQL2005 SQL2008

  • 它不适用于的开发人员:
  • 开发 4:Windows 7 x64,SQL2008 SQL2005
  • 开发 5:Windows Vista x86、SQL2005
  • 开发 6:Windows XP X86、SQL2005
  • 我的家用电脑:Windows Vista 家庭高级版、x86、SQL2005

  • 我应该补充一点,为了追查问题,所有机器都已完全修补了 Microsoft 更新中可用的所有内容。

    更新 1:
  • http://social.msdn.microsoft.com/forums/en-US/windowstransactionsprogramming/thread/a5462509-8d6d-4828-aefa-a197456081d3/ 描述了一个类似的问题......早在 2006 年!
  • http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope%28VS.80%29.aspx - 阅读该代码示例,它清楚地展示了将升级为 DTC 的嵌套第二个连接(实际上是到第二个 SQL 服务器)。我们没有在我们的代码中这样做 - 我们没有使用不同的 SQL 服务器,也没有不同的连接字符串,也没有嵌套的辅助连接打开 - 不应该升级到 DTC。
  • http://davidhayden.com/blog/dave/archive/2005/12/09/2615.aspx(从 2005 年开始)讨论了在连接到 SQL2000 时如何始终升级到 DTC。我们使用的是 SQL2005/2008
  • http://msdn.microsoft.com/en-us/library/ms229978.aspx MSDN 关于事务升级。

  • 该 MSDN 事务升级页面指出以下情况将导致事务升级为 DTC:
  • 至少一个不支持单阶段通知的持久资源被登记在事务中。
  • 事务中至少登记了两个支持单阶段通知的持久资源。例如,登记单个连接不会导致事务被提升。但是,每当您打开与数据库的第二个连接导致数据库登记时,System.Transactions 基础结构会检测到它是事务中的第二个持久资源,并将其升级为 MSDTC 事务。
  • 调用将事务“编码”到不同应用程序域或不同进程的请求。例如,跨应用程序域边界的事务对象的序列化。事务对象是按值编码的,这意味着任何跨应用程序域边界(即使在同一进程中)传递它的尝试都会导致事务对象的序列化。您可以通过调用将事务作为参数的远程方法来传递事务对象,也可以尝试访问远程事务服务组件。这会序列化事务对象并导致升级,就像跨应用程序域序列化事务一样。它正在分发,本地事务管理器不再适用。

  • 我们没有遇到#3。 #2 没有发生,因为一次只有一个连接,而且它也是一个“持久资源”。有没有办法让#1 发生?某些 SQL2005/8 配置导致它不支持单阶段通知?

    更新 2:

    个人重新调查了一下,大家的SQL Server版本——“Dev 3”其实是SQL2008,“Dev 4”其实是SQL2005。这将教会我永远不要再相信我的同事。 ;) 由于数据的这种变化,我很确定我们已经找到了我们的问题。我们的 SQL2008 开发人员没有遇到这个问题,因为 SQL2008 包含了大量 SQL2005 没有的功能。

    它还告诉我,因为我们将支持 SQL2005,所以我们不能像以前那样使用 TransactionScope,如果我们想使用 TransactionScope,我们将需要传递一个 SqlConnection 对象......这在 SqlConnection 不能轻易传递的情况下似乎有问题......它只是全局 SqlConnection 实例的味道。皮尤!

    更新 3

    只是为了在问题中澄清:

    SQL2008:
  • 允许单个 TransactionScope 内的多个连接(如上面的示例代码所示。)
  • 警告#1:如果那些多个SqlConnection 是嵌套的,即同时打开两个或多个SqlConnection,TransactionScope 将立即升级为DTC。
  • 警告 #2:如果一个额外的 SqlConnection 被打开到不同的“持久资源”(即:不同的 SQL Server),它将立即升级为 DTC

  • SQL2005:
  • 不允许在单个 TransactionScope 期间内有多个连接。当/如果打开第二个 SqlConnection 时,它会升级。

  • 更新 4

    为了让这个问题变得更有用,并且为了更清楚起见,这里是如何使用单个 SqlConnection 将 SQL2005 升级到 DTC 的方法:
    using (TransactionScope transactionScope = new TransactionScope()) {
       using (SqlConnection connection = new SqlConnection(connectionString)) {
          connection.Open();
          connection.Close();
          connection.Open(); // escalates to DTC
       }
    }
    

    这对我来说似乎很糟糕,但我想我能理解是否每次调用 SqlConnection.Open() 都是从连接池中获取的。

    “可是,为什么会这样呢?”好吧,如果您在该连接打开之前对其使用 SqlTableAdapter,SqlTableAdapter 将打开和关闭连接,有效地为您完成事务,因为您现在无法重新打开它。

    因此,基本上,为了成功地将 TransactionScope 与 SQL2005 一起使用,您需要有某种全局连接对象,该对象从第一个 TransactionScope 实例化开始一直保持打开状态,直到不再需要它为止。除了全局连接对象的代码味道之外,首先打开连接并最后关闭连接与尽可能晚地打开连接并尽快关闭连接的逻辑不一致。

    最佳答案

    SQL Server 2008 可以使用多个 SQLConnection合二为一 TransactionScope不升级,前提是连接不是同时打开的,这将导致多个“物理”TCP 连接,因此需要升级。

    我看到您的一些开发人员使用 SQL Server 2005,而其他开发人员使用 SQL Server 2008。您确定您正确识别了哪些正在升级,哪些没有?

    最明显的解释是使用 SQL Server 2008 的开发人员没有升级。

    关于c# - TransactionScope 在某些机器上自动升级到 MSDTC?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1690892/

    相关文章:

    c# - 字段从未分配给它,并且其默认值始终为null(CS0649)

    c# - 使用 asp.net 遍历文本框

    c# - 从 ListBox 中删除项目时,每个循环都不起作用

    c# - 如何自动设置 DateCreated 和 DateUpdated

    c# - 如何在向导事件步骤中执行 SQL 插入?

    c# - 检查组合框中的特定值

    .net - 什么决定了 System.Net.IPAddress.ToString() 的 IPv6 地址格式?

    entity-framework-4 - 如何在多个 DbContext 类中强制只进行一项事务?

    java - EclipseLink - 并发异常 - signalAttemptedBeforeWait

    sql-server - SQL Server sys.databases log_reuse_wait 问题