在我们的项目中,我们使用 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();
}
我们真的深入挖掘并试图解决这个问题。以下是有关它工作的机器的一些信息:
它不适用于的开发人员:
我应该补充一点,为了追查问题,所有机器都已完全修补了 Microsoft 更新中可用的所有内容。
更新 1:
该 MSDN 事务升级页面指出以下情况将导致事务升级为 DTC:
我们没有遇到#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:
SQL2005:
更新 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/