在某些机器上,TransactionScope自动升级为MSDTC ?

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

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

这真的让我摸不着头脑,并让我认真考虑回到一个基于ADO的自制的类似transactionscope的解决方案。NET事务对象。这看起来很疯狂——同样的代码在我们的开发人员的的一半上工作(并且不升级),在另一个开发人员的上升级。

我希望跟踪事务升级到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();
}

我们已经深入研究并试图解决这个问题。这里有一些关于它工作的机器的信息:

  • 开发1:Windows 7 x64 SQL2008
  • Dev 2: Windows 7 x86 SQL2008
  • Dev 3: Windows 7 x64 SQL2005 SQL2008 . txt

不适用的开发人员:

  • Dev 4: Windows 7 x64, SQL2008 SQL2005
  • 开发5:Windows Vista x86, SQL2005
  • Dev 6: Windows XP X86, SQL2005
  • 我的家庭电脑:Windows Vista家庭高级版,x86, SQL2005

我应该补充一点,为了找到问题,所有的机器都已经用微软更新提供的所有东西打了完整的补丁。

更新1:

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

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

我们没有经历第三种情况。#2没有发生,因为一次只有一个连接,而且它也是连接到单个“持久资源”。有可能发生第一条吗?某些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:如果那些多个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开始一直保持打开状态,直到不再需要为止。除了全局连接对象的代码气味之外,首先打开连接并最后关闭它与尽可能晚打开连接和尽快关闭连接的逻辑是不一致的。

78721 次浏览

如果在内部使用多个连接,TransactionScope总是升级为DTC事务。上面的代码在禁用DTC的情况下工作的唯一方法是,如果您两次从连接池中获得相同的连接,那么可能性很大。

问题是,在我们一半的开发人员机器上,我们可以在禁用MSDTC的情况下运行。 你确定它被禁用了吗;)

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

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

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

当连接到2005时,代码会导致升级。

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

SQL Server 2008中的可推广事务

.NET Framework 2.0版本 和SQL Server 2005,打开第二个 TransactionScope内的连接 会自动提升 事务到完全分布式 事务,即使是两个连接 使用相同的连接 字符串。在这种情况下,是分布式的 事务增加不必要的开销

从SQL Server 2008开始 .NET框架3.5版, 本地事务不再存在 提升到分布式事务 中打开了另一个连接 之前的交易之后 交易结束。这需要 如果是,则无需更改代码 已经使用连接池和

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

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

enter image description here

看到避免不必要的升级到分布式事务

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

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

    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();
}
}

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

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

  1. 在连接字符串上设置Enlist=false以避免交易时自动征募。

  2. 在事务范围内
  3. 手动将连接注册为参与者。(原文过时的) 或者这样做:如何防止MSDTC自动升级 (archive.is)

确保你的connectionString没有将池化设置为false。这将为TransactionScope中的每个新的SqlConnection创建一个新连接,并将其升级为DTC。