TransactionScope automatically escalating to MSDTC on some machines?
在我们的项目中,我们使用TransactionScope来确保数据访问层在事务中执行它的操作。我们的目标是不要求在最终用户的机器上启用MSDTC服务。
问题是,在我们一半的开发人员机器上,我们可以在禁用msdtc的情况下运行。另一半必须启用它,否则会收到"msdtc on[server]is unavailable"错误消息。
这真的让我抓耳挠腮,让我认真考虑回到一个基于ADO.NET事务对象的自选TransactionScope类解决方案。这看起来是疯狂的-在我们的开发人员的一半上工作(并且不升级)的相同代码在另一个开发人员的上升级。
我希望找到一个更好的答案来追踪交易升级到DTC的原因,但不幸的是它没有。
下面是一个将导致故障的代码示例,在尝试升级的计算机上,它尝试在第二个connection.open()上升级(是的,当时没有打开其他连接)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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
- 开发2:Windows 7 x86 SQL2008
- dev 3:windows 7 x64
sql2005sql2008
它不适用的开发人员:
- dev 4:windows 7 x64,
sql2008sql2005 - 开发5:Windows Vista x86,sql2005
- dev 6:Windows XP x86,sql2005
- 我的家用电脑:Windows Vista Home Premium、x86、SQL2005
我应该补充一点,为了解决这个问题,所有的机器都已经完全修复了Microsoft Update提供的所有功能。
更新1:- http://social.msdn.microsoft.com/forums/en-us/windowstransactionsprogramming/thread/a5462509-8d6d-4828-aefa-a197456081d3/描述了一个类似的问题…回到2006年!
- http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope%28vs.80%29.aspx-阅读该代码示例,它清楚地演示了一个嵌套的第二个连接(实际上是到第二个SQL服务器),它将升级为DTC。我们的代码中没有这样做——我们没有使用不同的SQL服务器,也没有不同的连接字符串,也没有打开嵌套的辅助连接——不应该升级到DTC。
- http://davidhayden.com/blog/dave/archive/2005/12/09/2615.aspx(2005年起)讨论了连接到sql2000时如何始终升级到DTC。我们使用的是SQL2005/2008
- http://msdn.microsoft.com/en-us/library/ms229978.aspx msdn on transaction escalation.
"msdn事务升级"页说明以下情况将导致事务升级到DTC:
我们没有体验到3。#2不会发生,因为一次只有一个连接,而且它也是一个单一的"持久资源"。有没有可能发生这种情况?某些SQL2005/8配置导致它不支持单阶段通知?
更新2:我个人重新调查了每个人的SQL Server版本——"dev 3"实际上有sql2008,而"dev 4"实际上是sql2005。这将教会我不再信任我的同事。;)由于数据的变化,我确信我们已经找到了问题所在。我们的sql2008开发人员没有遇到这个问题,因为sql2008包含了大量sql2005所没有的令人敬畏的内容。
它也告诉我,因为我们要
如果连接不同时打开,SQL Server 2008可以在一个
我看到您的一些开发人员有SQL Server 2005,另一些开发人员有SQL Server 2008。您确定已正确识别哪些正在升级,哪些没有升级?
最明显的解释是,使用SQL Server 2008的开发人员不会升级。
我对这个话题的研究结果是:
请参阅避免不必要的升级到分布式事务
我仍在调查Oracle的升级行为:跨越到同一数据库的多个连接的事务是否升级为DTC?
当连接到2005年时,该代码将导致升级。
查看msdn上的文档-http://msdn.microsoft.com/en-us/library/ms172070.aspx
Promotable Transactions in SQL Server 2008
In version 2.0 of the .NET Framework
and SQL Server 2005, opening a second
connection inside a TransactionScope
would automatically promote the
transaction to a full distributed
transaction, even if both connections
were using identical connection
strings. In this case, a distributed
transaction adds unnecessary overhead
that decreases performance.Starting with SQL Server 2008 and
version 3.5 of the .NET Framework,
local transactions are no longer
promoted to distributed transactions
if another connection is opened in the
transaction after the previous
transaction is closed. This requires
no changes to your code if you are
already using connection pooling and
enlisting in transactions.
我无法解释为什么dev 3:windows 7 x64、sql2005成功,dev 4:windows7x64失败。你确定那不是反过来的吗?
我不知道为什么这个答案被删除了,但这似乎有一些相关的信息。
8月4日10点17:42爱德华多回答
在连接字符串上设置enlist=false,以避免在事务上自动登记。
手动将连接登记为事务范围中的参与者。[原始文章过时]或者这样做:如何阻止自动msdtc升级[存档.is]
我不太确定嵌套连接是否是问题所在。我正在调用SQL Server的本地实例,但它不会生成DTC??
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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(); } } |
如果在内部使用的访问权限超过1个,则TransactionScope始终升级为DTC事务。上述代码在禁用DTC的情况下工作的唯一方法是,如果您两次都从连接池获得相同的连接,这是非常有可能的。
"问题是,在我们一半的开发人员机器上,我们可以在禁用msdtc的情况下运行。"是否确定已禁用;)