在我们的项目中,我们使用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();
}
我们已经深入研究并试图解决这个问题。这里有一些关于它工作的机器的信息:
不适用的开发人员:
我应该补充一点,为了找到问题,所有的机器都已经用微软更新提供的所有东西打了完整的补丁。
该MSDN事务升级页面指出,以下条件将导致事务升级到DTC:
我们没有经历第三种情况。#2没有发生,因为一次只有一个连接,而且它也是连接到单个“持久资源”。有可能发生第一条吗?某些SQL2005/8配置导致它不支持单阶段通知?
重新调查,我个人,每个人的SQL Server版本——“Dev 3”实际上有SQL2008,而“Dev 4”实际上是SQL2005。这教训了我再也不要相信我的同事了。,)由于数据的变化,我很确定我们找到了问题所在。我们的SQL2008开发人员没有遇到这个问题,因为SQL2008包含了大量SQL2005所没有的令人敬畏的功能。
它还告诉我,因为我们将支持SQL2005,我们不能像以前那样使用TransactionScope,如果我们想使用TransactionScope,我们将需要传递一个SqlConnection对象…在SqlConnection不能轻易传递的情况下,这似乎是有问题的…它只是闻起来像global-SqlConnection实例。皮尤!
在这个问题中澄清一下
SQL2008:
SQL2005:
为了使这个问题更加一团糟有用,并且为了更清楚起见,下面是如何使用单 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开始一直保持打开状态,直到不再需要为止。除了全局连接对象的代码气味之外,首先打开连接并最后关闭它与尽可能晚打开连接和尽快关闭连接的逻辑是不一致的。