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

TransactionScope automatically escalating to MSDTC on some machines?

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

问题是,在我们一半的开发人员机器上,我们可以在禁用msdtc的情况下运行。另一半必须启用它,否则会收到"msdtc on[server]is unavailable"错误消息。

这真的让我抓耳挠腮,让我认真考虑回到一个基于ADO.NET事务对象的自选TransactionScope类解决方案。这看起来是疯狂的-在我们的开发人员的一半上工作(并且不升级)的相同代码在另一个开发人员的上升级。

我希望找到一个更好的答案来追踪交易升级到DTC的原因,但不幸的是它没有。

下面是一个将导致故障的代码示例,在尝试升级的计算机上,它尝试在第二个connection.open()上升级(是的,当时没有打开其他连接)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
  • dev 3:windows 7 x64sql2005sql2008

它不适用的开发人员:

  • dev 4:windows 7 x64,sql2008sql2005
  • 开发5:Windows Vista x86,sql2005
  • dev 6:Windows XP x86,sql2005
  • 我的家用电脑:Windows Vista Home Premium、x86、SQL2005

我应该补充一点,为了解决这个问题,所有的机器都已经完全修复了Microsoft Update提供的所有功能。

更新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-阅读该代码示例,它清楚地演示了一个嵌套的第二个连接(实际上是到第二个SQL服务器),它将升级为DTC。我们的代码中没有这样做——我们没有使用不同的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 on transaction escalation.

"msdn事务升级"页说明以下情况将导致事务升级到DTC:

  • 事务中至少登记了一个不支持单阶段通知的持久资源。
  • 事务中至少登记了两个支持单阶段通知的持久资源。例如,使用登记单个连接不会导致提升事务。但是,每当打开与数据库的第二个连接导致数据库登记时,System.Transactions基础结构会检测到它是事务中的第二个持久资源,并将其升级为MSDTC事务。
  • 调用将事务"封送"到不同应用程序域或不同进程的请求。例如,跨应用程序域边界对事务对象进行序列化。事务对象是按值封送的,这意味着任何试图将其通过应用程序域边界(甚至在同一进程中)的尝试都会导致事务对象的序列化。可以通过调用将事务作为参数的远程方法来传递事务对象,也可以尝试访问远程事务服务组件。这将序列化事务对象并导致升级,就像在应用程序域中序列化事务一样。它正在被分发,并且本地事务管理器不再足够。
  • 我们没有体验到3。#2不会发生,因为一次只有一个连接,而且它也是一个单一的"持久资源"。有没有可能发生这种情况?某些SQL2005/8配置导致它不支持单阶段通知?

    更新2:

    我个人重新调查了每个人的SQL Server版本——"dev 3"实际上有sql2008,而"dev 4"实际上是sql2005。这将教会我不再信任我的同事。;)由于数据的变化,我确信我们已经找到了问题所在。我们的sql2008开发人员没有遇到这个问题,因为sql2008包含了大量sql2005所没有的令人敬畏的内容。

    它也告诉我,因为我们要


    如果连接不同时打开,SQL Server 2008可以在一个TransactionScope中使用多个SQLConnection,而不会升级,这将导致多个"物理"TCP连接,因此需要升级。

    我看到您的一些开发人员有SQL Server 2005,另一些开发人员有SQL Server 2008。您确定已正确识别哪些正在升级,哪些没有升级?

    最明显的解释是,使用SQL Server 2008的开发人员不会升级。


    我对这个话题的研究结果是:

    enter image description here

    请参阅避免不必要的升级到分布式事务

    我仍在调查Oracle的升级行为:跨越到同一数据库的多个连接的事务是否升级为DTC?


    当连接到2005年时,该代码将导致升级。

    查看msdn上的文档-http://msdn.microsoft.com/en-us/library/ms172070.aspx

    Promotable Transactions in SQL Server 2008

    In version 2.0 of the .NET Framework
    and SQL Server 2005, opening a second
    connection inside a TransactionScope
    would automatically promote the
    transaction to a full distributed
    transaction, even if both connections
    were using identical connection
    strings. In this case, a distributed
    transaction adds unnecessary overhead
    that decreases performance.

    Starting with SQL Server 2008 and
    version 3.5 of the .NET Framework,
    local transactions are no longer
    promoted to distributed transactions
    if another connection is opened in the
    transaction after the previous
    transaction is closed. This requires
    no changes to your code if you are
    already using connection pooling and
    enlisting in transactions.

    我无法解释为什么dev 3:windows 7 x64、sql2005成功,dev 4:windows7x64失败。你确定那不是反过来的吗?


    我不知道为什么这个答案被删除了,但这似乎有一些相关的信息。

    8月4日10点17:42爱德华多回答

  • 在连接字符串上设置enlist=false,以避免在事务上自动登记。

  • 手动将连接登记为事务范围中的参与者。[原始文章过时]或者这样做:如何阻止自动msdtc升级[存档.is]


  • 我不太确定嵌套连接是否是问题所在。我正在调用SQL Server的本地实例,但它不会生成DTC??

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
        public void DoWork2()
        {
            using (TransactionScope ts2 = new TransactionScope())
            {
                using (SqlConnection conn1 = new SqlConnection("Data Source=Iftikhar-PC;Initial Catalog=LogDB;Integrated Security=SSPI;"))
                {
                    SqlCommand cmd = new SqlCommand("Insert into Log values(newid(),'" +"Dowork2()" +"','Info',getDate())");
                    cmd.Connection = conn1;
                    cmd.Connection.Open();
                    cmd.ExecuteNonQuery();

                    using (SqlConnection conn2 = new SqlConnection("Data Source=Iftikhar-PC;Initial Catalog=LogDB;Integrated Security=SSPI;Connection Timeout=100"))
                    {
                        cmd = new SqlCommand("Insert into Log values(newid(),'" +"Dowork2()" +"','Info',getDate())");
                        cmd.Connection = conn2;
                        cmd.Connection.Open();
                        cmd.ExecuteNonQuery();
                    }
                }

                ts2.Complete();
            }
        }


    如果在内部使用的访问权限超过1个,则TransactionScope始终升级为DTC事务。上述代码在禁用DTC的情况下工作的唯一方法是,如果您两次都从连接池获得相同的连接,这是非常有可能的。

    "问题是,在我们一半的开发人员机器上,我们可以在禁用msdtc的情况下运行。"是否确定已禁用;)