DotNet 2.0 事务模型
在微软DotNet2.0中引进新的命名空间System.Transactions,具有本地简单的事务模型。它解决1.1事务缺点。
在DotNet中有两种类型的事务,分别适合于不同情况。第一种是ADO.NET 提供的。第二种是企业事务服务。我们先看一看1.1版本的事务类型:
ADO.NET事务模型
作为DotNet数据提供程序的一部分的事务处理模型,使用起来很简单。如下例:
C# Code
SqlConnection con = new SqlConnection("Connection String");
SqlTransaction tr = con.BeginTransaction();
SqlCommand cmd = new SqlCommand("Update Account set Balance=500 where AccountId=52", con, tr);
try
{
cmd.ExecuteNonQuery();
tr.Commit();
}
catch (Exception exc)
{
tr.Rollback();
}
finally
{
con.Close();
}
利用连接对象创建一个事务对象tr,并将该事务关联到SqlCommand对象cmd。执行完命令后,根据情况决定是否进行提交或者回滚。
似乎ADO.NET事务模型不错。但是还存在几个问题:.如果数据操作在多个数据库之间进行,这个模型就有问题。因为每个事务在一个连接上创建的。另外,在对象环境下,使用数据库事务方式也不理想。在面向对象环境中,许多对象协作完成一个业务流程。如果业务流程具有事务性,那么就需要在各个对象之间传递事务对象。这需要额外编写代码。
企业服务事务
企业服务事务通过两段提交和分布式事务管理器解决了绝大部分的ADO.NET事务问题。两段提交和分布式事务管理器确保事务独立于数据库。并以声明的方式进行使用事务。
下列AccountManager类的TransferCash方法接受两个帐号参数,在两个帐号之间进行现金划转。
C# Code
[Transaction(TransactionOption.Required)]
class AccountManager : ServicedComponent
{
[AutoComplete()]
void TransferCash(Account from, Account to, double amt)
{
from.Withdraw(amt);
to.Deposit(amt);
}
}
在上述代码中,我们并没有显式创建事务对象。只是用声明属性方法说明对象的事务属性。Autocomplete属性说明如果没有错误产生则提交事务。TransactionOption.Required 参数的Transaction属性指明AccountManager 是事务性的,并应该在事务下运行。
通过使用这种事务模型,我们就可以访问多个数据源,并将它们放在一个事务中。在上述代码中,.取钱对一个数据库操作,存钱则可以更新另一个数据库。
但是,这仍然存在问题。第一,类必须从ServicedComponent继承,才能使用企业服务事务。在单继承模型中,这种方法无疑影响业务类无法从其他类继承。
第二、企业服务事务总是作为分布式事务方式运行,即使使用一个数据库,企业服务事物仍然按照分布式处理。这样,系统就需要更多的资源。
第三、创建的组件需要安装到COM+服务器中。尽管,DotNet大大简化安装步骤,但仍然需要强类型名称并且正确地配置。
System.Transactions命名空间介绍
System.Transactions模型是DotNet2.0中新增的。其目标就是解决上述问题,它结合ADO.NET 和企业服务事务特色。
在System.Transactions命名空间中,可以使用TransactionScope 对象处理一系列操作并分组为一个事务。下列代码创建了和上面使用企业服务事务具有相同的事务功能。
C# Code
class AccountManager
{
void TransferCash(Account from, Account to, double amt)
{
using(TransactionScope scope=new TransactionScope())
{
from.Withdraw(amt);
to.Deposit(amt);
scope.Complete();
}
}
}
在上面的代码中,我们并没有从具有事务性的类继承。我们只是使用TransactionScope对象并用Using代码块进行方法包装来访问数据库。成功后,调用对象scope的Complete 方法告诉事务进行提交。如果出现错误,就不会调用Scope的Complete方法,事务回滚。
System.Transactions有一个属性标识是否使用分布式事务。如果只是在一个应用程序域并访问一个数据库那么就可以使用本地事务。否则,可以使用类似于企业服务事务模型的分布式事务。
在多数情况下,我们会使用TransactionScope 对象处理事务。我们也可以进行事务嵌套,这样就提供了一个选项来确定各个事务之间的逻辑关系。下面方法是在取钱成功时进行数据记录。
C# Code
void LogWithdrawals(Account account,double amt)
{
using (TransactionScope scope = new TransactionScope (TransactionScopeOption.Required))
{
//database calls to log details
}
}
代码创建一个TransactionScope对象,事务属性设置为TransactionScopeOption.Required。指示代码应该在事务中运行。如果当前有一个事务,则加入到当前事务,否则创建一个事务。其他可选事务属性有:RequiresNew (总是创建一个新事务)和Suppress (不加入事务)。这样可以实现事务之间的逻辑关系。
也可以使用TransactionOption 对象决定事务的隔离级别和超时设置。如下例:
C# Code
TransactionOptions options = new TransactionOptions();
options.IsolationLevel = IsolationLevel.ReadCommitted;
options.Timeout = new TimeSpan(0, 1, 0);
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew,options))
{
//code within transaction
}
代码中设置事务的隔离级别为read committed超时为1分钟。
结论:
System.Transactions是DotNet 2.0的数据模型,它解决了1.1版本的事务的缺点