TransactionScope会在某些机器上自动升级到MSDTC吗?

Yoo*_*eek 280 .net c# msdtc transactions transactionscope

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

麻烦的是,在我们开发人员的一半机器上,我们可以在禁用MSDTC的情况下运行.另一半必须启用它或他们得到"MSDTC on [SERVER] is unavailable"错误消息.

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

我希望得到一个更好的答案,跟踪为什么交易升级到DTC但不幸的是它没有.

这是一个会导致问题的示例代码,在尝试升级的机器上,它会尝试在第二个连接上升级.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();
}
Run Code Online (Sandbox Code Playgroud)

我们真的挖了进来并试图解决这个问题.以下是它所使用的机器的一些信息:

  • 开发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 Update提供的所有功能.

更新1:

该MSDN事务升级页面指出以下条件将导致事务升级到DTC:

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

我们没有遇到#3.#2没有发生,因为一次只有一个连接,它也是一个"持久资源".有没有办法#1可能发生?一些SQL2005/8配置导致它不支持单阶段通知?

更新2:

个人重新调查,每个人的SQL Server版本 - "Dev 3"实际上有SQL2008,而"Dev 4"实际上是SQL2005.这将教会我永远不要再相信我的同事.;)由于数据的这种变化,我很确定我们发现了我们的问题.我们的SQL2008开发人员没有遇到这个问题,因为SQL2008包含了SQL2005所没有的大量精彩内容.

它还告诉我,因为我们将支持SQL2005,我们不能像过去那样使用TransactionScope,如果我们想使用TransactionScope,我们将需要传递一个SqlConnection对象...这在SqlConnection无法轻易传递的情况下似乎有问题...它只是闻起来的global-SqlConnection实例.座位!

更新3

只是在问题中澄清一下:

SQL2008:

  • 允许在单个TransactionScope中进行多个连接(如上面的示例代码所示).
  • 警告#1:如果嵌套了多个SqlConnections,即同时打开两个或多个SqlConnections,TransactionScope将立即升级到DTC.
  • 警告#2:如果向另一个"持久资源"(即:不同的SQL Server)打开了一个额外的SqlConnection ,它将立即升级到DTC

SQL2005:

  • 在单个TransactionScope期间不允许多个连接.当/如果打开第二个SqlConnection时,它将升级.

更新4

在做出这个问题更加的利益乱七八糟的有用的,只是为了更清晰起见,这里是你如何能得到SQL2005升级到DTC带有 SqlConnection:

using (TransactionScope transactionScope = new TransactionScope()) {
   using (SqlConnection connection = new SqlConnection(connectionString)) {
      connection.Open();
      connection.Close();
      connection.Open(); // escalates to DTC
   }
}
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎有些不妥,但我想我能理解每次通话SqlConnection.Open()都是从连接池中获取的.

"为什么会发生这种情况呢?" 好吧,如果在打开之前对该连接使用SqlTableAdapter,SqlTableAdapter将打开并关闭连接,为您有效地完成事务,因为您现在无法重新打开它.

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

Joe*_*Joe 71

如果连接未同时打开,SQL Server 2008可以SQLConnectionTransactionScope不升级的情况下使用多个s ,这将导致多个"物理"TCP连接,因此需要升级.

我看到你的一些开发人员拥有SQL Server 2005而其他人拥有SQL Server 2008.你确定你已经正确识别哪些正在升级而哪些不升级?

最明显的解释是SQL Server 2008的开发人员不会升级.

  • 你和hwiechers是对的.我脸上都有鸡蛋.谢谢你用线索打我.:)因为你是第一个,你得到答案.我想补充一点澄清 - SQL2008允许打开多个连接,但不能同时打开.在任何给定时间仍然只能打开一个连接,或者TransactionScope将升级到DTC. (19认同)

Pet*_*inl 58

我对这个主题的研究结果:

在此输入图像描述

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

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


hwi*_*ers 31

连接到2005时,该代码导致升级.

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

SQL Server 2008中的可升级事务

在.NET Framework和SQL Server 2005的2.0版中,在TransactionScope内部打开第二个连接会自动将事务提升为完整的分布式事务,即使两个连接都使用相同的连接字符串也是如此.在这种情况下,分布式事务会增加不必要的开销,从而降低性能

从SQL Server 2008和.NET Framework 3.5版开始,如果在上一个事务关闭后在事务中打开另一个连接,则不再将本地事务提升为分布式事务.如果您已经在使用连接池并在事务中登记,则不需要更改代码.

我无法解释为什么Dev 3:Windows 7 x64,SQL2005成功和Dev 4:Windows 7 x64失败.你确定不是反过来吗?


Chr*_*sic 10

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

2010年8月4日17:42 Eduardo回答

  1. 在连接字符串上设置Enlist = false以避免在事务上自动登记.

  2. 手动登记连接作为事务范围的参与者.[ 原始文章过时]或这样做:如何防止自动MSDTC推广 [archive.is]