一. 实现事务控制理论
实际上所有用于更新数据源的面向商业的应用程序都需要事务处理支持。通过提供四个基本担保,即众所周知的首字缩写ACID:可分性,一致性,分离性,和耐久性,事务处理将用于确保包含在一个或多个数据源中的系统的完整性。
可以采用很多方法将事务管理合并到数据访问代码中。每种方法适合下面三种基本编程模型之一。
- 手工事务处理。可以直接在组件代码或存储过程中分别编写利用ADO.NET 或 Transact-SQL事务处理支持特性的代码。
- 可提升事务处理.SQL Server2005 .NET Framework2.0 提供程序支持可提升事务;可提升事务通过将分布式事务推迟到需要时再创建,对分布式事务进行优化。如果只需要一个资源管理器,则不会发生任何分布式事务。
- 自动化(COM+)事务处理。可以向.NET类中增加声明在运行时指定对象事务处理需要的属性。这种模型使你能方便地配置多个组件以使它们在同一事务处理内运行。
尽管自动化事务处理模型极大地简化了分布式事务处理过程,但三种模型都用于执行本地事务处理(即对单个资源管理器如SQL Server 2000执行的事务处理)或分布式事务处理(即,对位于远程计算机上的多个资源管理执行的事务处理)。
二. 实现方式
2.1 手工事务处理
![](http://luoz/note/files/endregion.gif)
SqlConnection conn = new SqlConnection(SqlHelper.ConnectionStringProfile); conn.Open(); SqlTransaction trans = conn.BeginTransaction(IsolationLevel.ReadCommitted); try { SqlHelper.ExecuteNonQuery(trans, CommandType.Text, sqlDelete, param); SqlHelper.ExecuteNonQuery(trans, CommandType.Text, sqlInsert, parms); trans.Commit(); } catch(Exception e) { trans.Rollback(); throw new ApplicationException(e.Message); } finally { conn.Close(); }
2.2 可提升事务处理
![](http://luoz/note/files/endregion.gif)
using (TransactionScope transScope = new TransactionScope()) { using (SqlConnection connection1 = new SqlConnection(connectString1)) { // Opening connection1 automatically enlists it in the // TransactionScope as a lightweight transaction. connection1.Open(); // Do work in the first connection. // Assumes conditional logic in place where the second // connection will only be opened as needed. using (SqlConnection connection2 = new SqlConnection(connectString2)) { // Open the second connection, which enlists the // second connection and promotes the transaction to // a full distributed transaction. connection2.Open(); // Do work in the second connection. } } // The Complete method commits the transaction. transScope.Complete(); } |
2.3 COM+事务处理
具体参见文档Csharp编写COM+组件步骤
三. 选择事务处理模型
在选择事务处理模型前,首先应当考虑是否真正需要事务处理。事务处理是服务器应用程序使用的最昂贵的资源,在不必要使用的地方,它们降低了扩展性。考虑下面用于管理事务处理使用的准则:
- 只在需要跨一组操作获取锁并需要加强ACID规则时才执行事务处理。
- 尽可能短地保持事务处理,以最小化维持数据库锁的时间。
- 永远不要将客户放到事务处理生命周期的控制之中。
- 不要为单个SQL语句使用事务处理。SQL Server自动把每个语句作为单个事务处理执行。
四. 自动化事务处理与手工事务处理的对比
尽管编程模型已经对自动化事务处理进行了简化,特别是在多个组件执行数据库更新时,但本地事务处理总是相当快,因为它们不需要与微软DTC交互。即使你对单个本地资源管理器(如SQL Server)使用自动化事务处理,也是这种情况(尽管性能损失减少了),因为手式本地事务处理避免了所有不必要的与DTC的进程间通信。
对于下面的情况,需使用手工事务处理:
- 对单个数据库执行事务处理。
对于下列情况,则宜使用自动事务处理:
- 需要将单个事务处理扩展到多个远程数据库时。
- 需要单个事务处理拥有多个资源管理器(如数据库和Windows 2000消息队列(被称为MSMQ)资源管理器)时。
4.1 使用手工事务处理
对于手工事务处理,可以直接在组件代码或存储过程中分别编写使用ADO.NET 或 Transact-SQL事务处理支持特性的代码。多数情况下,应选择在存储过程中控制事务处理,因为这种方法提供了更高的封装性,并且在性能方面,此方法与利用ADO.NET 代码执行事务处理兼容。
4.2 利用ADO.NET执行手工事务处理
ADO.NET支持事务处理对象,利用此对象可以开始新事务处理过程,并明确控制事务处理是否执行还是回滚。事务处理对象与单个数据库链接相关,可以通过链接对象的BeginTransaction方法获得。调用此方法并不是暗示,接下来的命令是在事务处理上下文中发出的。必须通过设置命令的Transaction属性,明确地将每个命令与事务处理关联起来。可以将多个命令对象与事务处理对象关联,因此在单个事务处理中就针对单个数据库把多个操作进行分组。
4.2.1 更多信息
- ADO.NET手工事务处理的默认分离级别是读联锁,这意味着在读取数据时,数据库控制共享锁,但在事务处理结束前,数据可以被修改。这种情况潜在地会产生不可重复的读取或虚数据。通过将事务处理对象的IsolationLevel属性设置为IsolationLevel枚举类型所定义的一个枚举值,就可改变分离级别。
- 必须仔细为事务处理选择合适的分离级别。其折衷是数据一致性与性能的比例。最高的分离等级(被序列化了)提供了绝对的数据一致性,但是以系统整体吞吐量为代价。较低的分离等级会使应用程序更易于扩展,但同时增加了因数据不一致而导致出错的可能性。对多数时间读取数据、极少写入数据的系统来说,较低的分离等级是合适的。
4.3 利用存储过程执行手工事务处理
也可以在存储过程中使用Transact-SQL语句直接控制手工事务处理。例如,可以利用包含了Transact-SQL事务处理语句(如BEGIN TRANSACTION、END TRANSACTION及ROLLBACK TRANSACTION)的存储过程执行事务处理。
更多信息
- 如果需要,可以在存储过程中使用SET TRANSACTION ISOLATION LEVEL语句控制事务处理的分离等级。读联锁是SQL Server的默认设置。关于SQL Server分离级别的更多信息,见SQL Server在线书目“访问和修改关系数据”一节中的分离级别部分。
使用自动化事务
自动化事务简化了编程模型,因为它们不需要明确地开始新事务处理过程,或明确执行或取消事务。然而,自动化事务的最大优点是它们能与DTC结合起来,这就使单个事务可以扩展到多个分布式数据源中。在大型分布式应用程序中,这个优点是很重要的。尽管通过手工对DTC直接编程来控制分布式事务是可能的,但自动化事务处理极大的简化了工作量,并且它是为基于组件的系统而设计的。例如,可以方便地以说明方式配置多个组件以执行包含了单个事务处理的任务。
自动化事务依赖于COM+提供的分布式事务处理支持特性。结果,只有服务组件(即从ServicedComponent类中派生的组件)能够使用自动化事务。
要为自动化事务处理配置类,操作如下:
- 从位于EnterpriseServices名称空间的ServicedComponent类中派生新类。
- 通过Transaction属性定义类的事务处理需求。来自TransactionOption的枚举值决定了如何在COM+类中配置类。可与此属性一同设置的其它属性包括事务处理分离等级和超时上限。
- 为了避免必须明确选出事务处理结果,可以用AutoComplete属性对方法进行注释。如果这些方法释放异常,事务将自动取消。注意,如果需要,仍可以直接挑选事务处理结果。