关于交易和msdtc的混淆

muh*_*han 9 .net msdtc transactions winforms

关于事务和msdtc如何协同工作,我有一些基本的困惑.

我有一个基本的服务器/客户端winforms应用程序.该应用程序使用transactionscope来封装在sql server上执行的几个sql命令.

当我在服务器上启用msdtc网络访问时,应用似乎工作正常.然后有一天它停止工作,说没有启用网络访问.

现在看来我必须在客户端计算机和服务器上启用msdtc网络访问才能使transactioncope工作.

客户端或服务器msdtc服务是否可以进行事务处理?或者两者兼而有之?

有没有人有关于客户端和服务器或服务器上是否需要msdtc网络访问的指导?

Ran*_*ica 11

如果您正在使用MSDTC,那么您将需要客户端(您的应用程序)和服务器(数据库)来运行MSDTC并且还要正确配置.

这可能是痛苦的根源,特别是在处理防火墙时.如果遇到问题,请参阅解决MSDTC问题.它谈论BizTalk,但它一般适用于MSDTC. DTCPING也是你的朋友.

现在,如果您使用的是SQL Server 2005及更高版本,只访问一个数据库,使用一个数据库连接并且未在应用程序域之间传递事务,那么您不应该要求使用MSDTC.在这些情况下,System.Transactions事务管理器将为您管理您的事务.如果发生任何先前的情况,则事务将被提升为分布式事务(并且事务管理器将是MSDTC).有关更多信息,请参阅事务管理升级.

一般情况下,如果您不需要,最好避免使用MSDTC.即如果您只处理单个SQL Server 2005+数据库,那么尝试将您的代码设计为不使用MSDTC.除了配置麻烦之外,DTC还会造成性能损失,因为对MSDTC的所有调用都与两阶段提交协议(MSDTC使用的协议)的开销相结合.

就你的具体情况而言,很难说.如果你的代码没有改变,那么防火墙规则可能已经改变了吗?我也看到Windows更新改变了DTC配置(为安全起见),这导致了一个问题.

根据评论更新:

为了监视事务提升或升级,如果您不使用任何分布式事务,我认为您可以使用某些分布式事务处理协调器性能计数器来跟踪已提交的事务.如果测试,您可以禁用MSDTC并查看您的代码是否失败.另一种方法是监视SQL Server中的事务.从编码角度来看,您可以尝试处理DistributedTransactionStarted事件并执行一些日志记录(但在进入生产之前删除该代码).

有关使用单个连接的代码示例,请转到MSDN 上的TransactionScope页面.基本上,创建一个TransactionScope,创建一个SqlConnection,用SqlConnection做一些工作,关闭连接,调用scope.Complete().

请注意,如果您使用的是数据适配器方法,它们会自动管理您的连接,以便关闭连接或将连接返回到连接池.无论哪种方式,如果调用另一个操作,那么事务将被提升为DTC事务.有关更多详细信息,请参阅System.Transactions和连接池.


Dan*_*iel 8

为了扩展@Tuzo的解释,下面是一个总是会升级的命令示例:

using(var scope = new TransactionScope())
{
  using(var conn = new SqlConnection(connString)){
     conn.Open();
     //...some command, etc.
  }
  using(var conn = new SqlConnection(connString)){
     conn.Open();
     //...some command, etc.
  }
  scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)

在实践中,连接和命令将在另一个类等,但你明白了.即使连接字符串是同一个数据库,它也会使用DTC升级,因为它是两个连接.非升级交易将是:

using(var scope = new TransactionScope())
{
  using(var conn = new SqlConnection(connString)){
     conn.Open();
     //...some command, etc.
     //...some other command, etc.
  }
  scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)

无论如何,这是更好的代码,因为您打开连接,执行您需要的操作,并尽快关闭.这确实意味着您必须考虑您的连接管理.根据您的应用程序,您可以采用不同的方式实现.例如:

using(var scope = new TransactionScope())
using(var conn = new SqlConnection(connString))
{
    conn.Open();
    var myService = new MyService(conn);
    var myService2 = new MyService2(conn);
    myService.DoSomething();
    myService2.DoSomething();
    scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)

有多种方法可以实现这一点.企业库数据访问应用程序块和各种ORM还可以帮助您更有效地处理连接和事务.