如何让你的生活更轻松。净交易升级行为


介绍

在。在2.0版中,微软引入了事务处理类。这个类提供了一个隐式编程模型,其中分布式事务由框架自动管理。

这种编程模型可以将本地事务自动提升/升级到由微软DTC管理的分布式事务。当创建新的事务范围时。Net framework将创建一个本地轻量级事务,当从同一个事务中访问两个或更多持久资源时,它将自动升级为分布式事务。

自动升级到分布式事务是TransactionScope类的一大优势,但也是它最大的弱点。很多程序员不知道这个特性,也不知道什么是分布式事务。

当您使用分布式事务时,您的计算机将不得不使用两阶段提交协议。该协议要求分布式事务中涉及的所有各方之间交换消息,以就事务的成功执行或失败达成一致。该协议引入了很大的开销,因为所有涉及的数据库都必须锁定事务中访问的资源,直到所有数据库都提交数据或者所有数据库都回滚。

但是您只使用一个数据库,所以您永远不必担心分布式事务的问题?错了。

SQL Server 2000

当您对此数据库使用事务处理时,所有的事务都会立即升级为分布式事务。因此,根据经验,除非您真的需要分布式事务,否则在这个数据库中应该始终使用显式的SqlTransaction。

SQL Server 2005

当您使用SQL server 2005时,TransactionScope类按预期工作;所有事务都将作为本地事务开始。但是意外的交易升级仍然会发生。

一个例子:

public void Transfer(double amount)
{
	using(TransactionScope ts = new TransactionScope())
	{
		Withdraw(amount);
		Deposit(amount);

		ts.Complete();
	}
}

public void Withdraw(double amount)
{
	using(DbConnection connection = new SqlConnection("connectionString"))
	{
		// Withdraw logic
	}
}

public void Deposit(double amount)
{
	using(DbConnection connection = new SqlConnection("connectionString"))
	{
		// Deposit logic
	}
}

乍一看,你可能认为没有问题?毕竟,我们只访问一个数据库?错了。SQL Server 2005将把到同一个数据库的两个连接视为两个不同的持久资源,事务将自动升级到分布式版本。

为了修复前面示例中的自动事务升级,一个正确的实现是将DbConnection显式传递给这两个方法。

public void Transfer(double amount)
{
	using(TransactionScope ts = new TransactionScope())
	{
		using(DbConnection connection = new SqlConnection("connectionString"))
		{
			Withdraw(connection, amount);
			Deposit(connection, amount);

			ts.Complete();
		}
	}
}

public void Withdraw(DbConnection connection, double amount)
{
	// Withdraw logic
}

public void Deposit(DbConnection connection, double amount)
{
	// Deposit logic
}

SQL Server 2008

SQL Server 2008比SQL Server 2005智能得多,可以自动检测某个事务中的所有数据库连接是否指向同一个物理数据库。如果是这种情况,事务仍然是本地事务,不会升级为分布式事务。不幸的是,有几个警告:

  • 如果打开的数据库连接是嵌套的,事务仍将升级为分布式事务。
  • 如果在事务中,建立了到另一个持久资源的连接,则事务会立即升级为分布式事务。


其他数据库

(大型)第三方数据库供应商的ADO.Net提供商通常至少应该遵守SQL Server 2005的行为。有关更多信息,我建议您查看特定数据库产品和版本的文档。

结论

Transactionscope类简化了事务处理,并使事务升级对用户透明。正因为如此,这是一个你会发现并且应该在大多数情况下使用的类。基于. Net的企业应用程序。但是,您必须了解与事务升级相关的详细信息,并且知道当您收到错误消息时应该做什么,例如“[SERVER]上的MSDTC不可用”。仅仅激活故障诊断码绝对不是正确的解决方案!表演之神会为此感谢你的。