在我们的项目中,我们使用TransactionScope来确保我们的数据访问层在事务中执行其动作。我们的目标是 不 要求在最终用户的计算机上启用MSDTC服务。
麻烦的是,在我们一半的开发人员机器上,我们可以在禁用MSDTC的情况下运行。另一半必须启用它,否则他们会收到 “ [SERVER]上 的 MSDTC不可用” 错误消息。
这真的让我抓狂了,还让我认真考虑回滚到基于ADO.NET事务对象的类似HomeScope的TransactionScope解决方案。这似乎是疯狂的- 在我们一半的开发人员的代码上起作用(并且不会升级)的同一代码 确实会 在其他开发人员的代码 上 升级。
我希望对Trace有了一个更好的答案,为什么交易会升级为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(); }
我们已经认真研究并试图解决这个问题。以下是适用于其的计算机的一些信息:
开发人员无法使用:
我应该补充说,所有计算机都已通过Microsoft Update的所有功能进行了全面修补,以解决问题。
MSDN事务升级页面指出以下情况将导致事务升级到DTC:
我们没有遇到#3。#2不会发生,因为一次只有一个连接,而且也连接到一个“持久资源”。有什么办法可能会发生#1?是否导致某些SQL2005 / 8配置不支持单阶段通知?
重新调查后,个人而言,每个人的SQL Server版本-“ Dev 3”实际上具有SQL2008,而“ Dev 4”实际上是SQL2005。那将教会我永远不要再信任我的同事。;)由于数据的这种变化,我很确定我们已经找到了问题。我们的SQL2008开发人员没有遇到此问题,因为SQL2008包括SQL2005没有的大量功能。
它还告诉我,因为我们将要支持SQL2005,所以我们不能像以前那样使用TransactionScope,并且如果我们想使用TransactionScope,我们将需要传递一个SqlConnection对象。在无法轻松传递SqlConnection的情况下,这似乎是有问题的…它只是闻到global- SqlConnection实例的味道。座位!
只是为了在这里澄清问题:
SQL2008:
SQL2005:
在做出这个问题更加的利益 乱七八糟的 有用的,只是为了更清晰起见,这里是你如何能得到SQL2005升级到DTC带有 单 SqlConnection:
SqlConnection
using (TransactionScope transactionScope = new TransactionScope()) { using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); connection.Close(); connection.Open(); // escalates to DTC } }
这对我来说似乎很困难,但是我想我可以理解是否每个呼叫SqlConnection.Open()都从连接池中获取。
SqlConnection.Open()
“为什么会这样呢?” 好吧,如果在打开该连接之前对它使用SqlTableAdapter,则SqlTableAdapter将打开和关闭该连接,为您有效地完成了事务,因为您现在无法重新打开它。
因此,基本上,为了在SQL2005上成功使用TransactionScope,您需要具有某种全局连接对象,该对象从第一个TransactionScope实例化到不再需要时保持打开状态。除了全局连接对象的代码气味外,首先打开连接并最后关闭它与延迟打开连接和尽快关闭连接的逻辑是矛盾的。
如果没有同时打开连接,则SQL Server 2008可以SQLConnection在TransactionScope不升级的情况下合用多个,这将导致多个“物理” TCP连接,因此需要升级。
SQLConnection
TransactionScope
我看到您的一些开发人员使用SQL Server 2005,其他开发人员使用SQL Server2008。您确定已正确确定哪些正在升级,哪些没有?
最明显的解释是,使用SQL Server 2008的开发人员没有升级。