使用事务范围实现隐式事务

TransactionScope 类提供一个简单方法,通过这一方法,您不必与事务本身交互,即可将代码块标记为参与某个事务。事务范围可以自动选择和管理环境事务。由于它易于使用并且效率很高,因此建议您在开发事务应用程序时使用 TransactionScope 类。

此外,您不必显式向事务登记资源。任何 System.Transactions 资源管理器(例如 SQL Server 2005)都可以检测到该范围创建的环境事务的存在并自动登记。

创建事务范围

下面的示例说明 TransactionScope 类的简单用法。

static public int CreateTransactionScope(
    string connectString1, string connectString2,
    string commandText1, string commandText2)
{

    int returnValue = 0;
    System.IO.StringWriter writer = new System.IO.StringWriter();

    using (TransactionScope scope = new TransactionScope())
    {
        using (SqlConnection connection1 = new SqlConnection(connectString1))
        {
            try
            {
                               connection1.Open();

                               SqlCommand command1 = new SqlCommand(commandText1, connection1);
                returnValue = command1.ExecuteNonQuery();
                writer.WriteLine("Rows to be affected by command1: {0}", returnValue);

                using (SqlConnection connection2 = new SqlConnection(connectString2))
                    try
                    {
                                               connection2.Open();

                                             returnValue = 0;
                        SqlCommand command2 = new SqlCommand(commandText2, connection2);
                        returnValue = command2.ExecuteNonQuery();
                        writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
                    }
                    catch (Exception ex)
                    {

                        writer.WriteLine("returnValue for command2: {0}", returnValue);
                        writer.WriteLine("Exception Message2: {0}", ex.Message);
                    }
            }
            catch (Exception ex)
            {

                writer.WriteLine("returnValue for command1: {0}", returnValue);
                writer.WriteLine("Exception Message1: {0}", ex.Message);
            }
        }

              scope.Complete();
    }

    if (returnValue > 0)
    {
        writer.WriteLine("Transaction was committed.");
    }
    else
    {
                writer.WriteLine("Transaction rolled back.");
    }

    Console.WriteLine(writer.ToString());

    return returnValue;
}

您创建了新的 TransactionScope 对象后,即开始事务范围。 如代码示例中所示,建议您使用 using 语句创建范围。C# 和 Visual Basic 中都提供 using 语句,其工作方式类似于 try...finally 块,可确保正确处理范围。

实例化 TransactionScope 时,事务管理器会确定要参与的事务。确定之后,该范围将始终参与此事务。这个决定基于两个因素:环境事务是否存在以及构造函数中 TransactionScopeOption 参数的值。环境事务是在其中执行代码的事务。您可以通过调用 Transaction 类的静态 Current 属性,获取对环境事务的引用。

完成事务范围

在您的应用程序完成了它要在某一事务中执行的所有工作后,应该只调用 Complete 方法一次,以便通知事务管理器它可以提交该事务。强烈建议将对 Complete 的调用作为最后一条语句放置在 using 块中。

如果调用此方法失败,则会中止该事务,因为事务管理器会将此解释为一个系统故障,或者与在事务范围内引发的异常等效的故障。但是,调用此方法并不确保将提交该事务。这只是一个向事务管理器通知您的状态的方法。在调用 Complete 方法后,您将无法再通过 Current 属性访问环境事务,这样做将会引发异常。

如果 TransactionScope 对象最初创建了该事务,则通过事务管理器提交该事务的实际工作将在 using 块中的最后一行代码后发生。如果它没有创建该事务,则只要 CommittableTransaction 对象的所有者调用了 Commit,就发生提交。在该时刻,事务管理器将基于对 TransactionScope 对象是否已调用了 Complete 方法,调用资源管理器并通知它们提交或回滚。

using 语句确保调用 TransactionScope 对象的 Dispose 方法,即使发生异常也是如此。Dispose 方法标记事务范围的结束。在调用此方法后发生的异常不会影响该事务。该方法还将环境事务还原为其以前的状态。

如果范围创建该事务,则引发 TransactionAbortedException,并中止该事务。如果事务管理器无法达成提交决定,则引发 TransactionIndoubtException。如果提交该事务,则不会引发任何异常。

回滚事务

要回滚某个事务,不应在该事务范围内调用 Complete 方法。例如,您可以在该范围内引发异常。该异常所参与的事务将被回滚。

使用 TransactionScopeOption 管理事务流

通过在使用自己范围的方法内调用使用 TransactionScope 的方法,可以嵌套事务范围,下例中的 RootMethod 方法即如此。

void RootMethod()
{
     using(TransactionScope scope = new TransactionScope())
     {
          /* Perform transactional work here */
          SomeMethod();
          scope.Complete();
     }
}

void SomeMethod()
{
     using(TransactionScope scope = new TransactionScope())
     {
          /* Perform transactional work here */
          scope.Complete();
     }
}

最顶部的事务范围称作根范围。

TransactionScope 类提供若干重载构造函数,这些构造函数接受 TransactionScopeOption 类型的枚举,此类型定义范围的事务性行为。

TransactionScope 对象具有三个选择:

  • 加入环境事务,或者在环境事务不存在时创建一个新的环境事务。
  • 成为新的根范围;即,开始一个新事务,并使该事务成为自己范围内的新环境事务。
  • 完全不参与事务。结果就是没有任何环境事务。

如果范围是用 Required 实例化的,并且存在一个环境事务,则该范围加入该事务。在另一方面,如果没有任何环境事务,则该范围将创建一个新事务,并且成为根范围。这是默认值。在使用 Required 时,无论该范围是根范围还是只是加入环境事务,其中的代码都不需要在行为上有什么不同。在这两种情况下它的操作完全相同。

如果范围是用 RequiresNew 实例化的,则它始终是根范围。它开始一个新事务,并且它的事务将成为该范围内的新环境事务。

如果该范围是用 Suppress 实例化的,则不管是否存在环境事务,它都永远不会参与某一事务。使用该值实例化的范围始终将 null 作为其环境事务。

TransactionScope 对象连接现有环境事务时,处置范围对象可能不会结束该事务,除非范围中止该事务。如果该环境事务是由根范围创建,则只有在处置根范围时,才对该事务调用 Commit。如果该事务是手动创建的,则该事务的创建者中止或提交该事务后该事务结束。

下面的示例说明一个 TransactionScope 对象,该对象创建三个嵌套的范围对象,每个对象都用不同的 TransactionScopeOption 值实例化。

using(TransactionScope scope1 = new TransactionScope())
//Default is Required
{
     using(TransactionScope scope2 = new
      TransactionScope(TransactionScopeOption.Required))
     {
     ...
     } 

     using(TransactionScope scope3 = new TransactionScope(TransactionScopeOption.RequiresNew))
     {
     ...
     } 

     using(TransactionScope scope4 = new
        TransactionScope(TransactionScopeOption.Suppress))
    {
     ...
    }
}

该示例说明一个不具有任何环境事务的代码块,它使用 Required 创建新范围 (scope1)。范围 scope1 是根范围,因为它创建一个新事务(事务 A)并使事务 A 成为环境事务。Scope1 然后再创建三个对象,每个对象都具有不同的 TransactionScopeOption 值。例如,scope2 是使用 Required 创建的,并且由于有一个环境事务,因此它连接 scope1 创建的第一个事务。请注意,scope3 是新事务的根范围,并且 scope4 不具有任何环境事务。

尽管 TransactionScopeOption 的默认值且最常用值是 Required,但其他每个值都各具不同用途。

如果您想要保留代码部分执行的操作,并且在操作失败的情况下不希望中止环境事务,则 Suppress 会对您很有帮助。例如,在您想要执行日志记录或审核操作时,或者在您想要向订户发布事件时(不管您的环境事务是提交还是中止),上述值就很有用。该值允许您在事务范围内具有非事务性的代码部分,如以下示例中所示。

using(TransactionScope scope1 = new TransactionScope())
{
     try
     {
          //Start of non-transactional section
          using(TransactionScope scope2 = new
             TransactionScope(TransactionScopeOption.Suppress))
          {
               //Do non-transactional work here
          }
          //Restores ambient transaction here
   }
     catch
     {}
   //Rest of scope1
}
时间: 2024-10-06 12:12:51

使用事务范围实现隐式事务的相关文章

基于TransactionScope类的分布式隐式事务

System.Transactions 命名空间中除了上一节中提到的基于 Transaction 类的显式编程模型,还提供使用 TransactionScope 类的隐式编程模型,它与显示编程模型相比,更加方便简单,它也是MSDN中建议使用的编程模型. 下面,我们基于TransactionScope类实现上一节银行转帐的例程. 示例代码: (1)SqlHelper.cs using System; using System.Collections.Generic; using System.Li

MYSQL中默认隐式事务及利用事务DML

一:默认情况下,MySQL采用autocommit模式运行.这意味着,当您执行一个用于更新(修改)表的语句之后,MySQL立刻把更新存储到磁盘中.默认级别为不可重复读. 二:会造成隐式提交的语句以下语句(以及同义词)均隐含地结束一个事务,似乎是在执行本语句前,您已经进行了一个COMMIT. (1)ALTER FUNCTION, ALTER PROCEDURE, ALTER TABLE, BEGIN, CREATEDATABASE, CREATE FUNCTION, CREATE INDEX, C

分布式隐式事务

public class SqlHelper { public static string GetConnection() { string connStr = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString; return connStr; }   public static int ExecuteNonQuery(string sql, params MySqlParameter

三大常用数据库事务详解之三:事务运行模式

三.事务的运行模式 通常,事务以3种模式运行,他们分别是: 1. 自动提交事务 每一条单独的SQL语句都在其执行完成后进行自动提交事务,即执行 SQL 语句后就会马上自动隐式执行 COMMIT 操作.如果出现错误,则进行事务回滚至之前状态. SQL SERVER和MY SQL中都默认开启自动提交事务,ORACLE则显式提交事务.这三种产品都提供了各自的方式来开闭自动提交事务模式,具体如下: 1)MYSQL中通过下面语句来开启或关闭当前会话或全局的自动提交事务模式. set session aut

Spring学习8-Spring事务管理(编程式事务管理)

一.Spring事务的相关知识   1.事务是指一系列独立的操作,但在概念上具有原子性. 比如转账:A账号-100, B账号+100,完成.这两个操作独立是没问题的. 但在逻辑上,要么全部完成,要么一起失败.    1)jdbc事务:每个Connection都带有一个事务,只是默认被设置为自动提交.一个连接可以有多个事务.对于JDBC,只有在同一个连接内,才有讨论是否提交的前提. 2)Hibernate事务:本质上也是使用JDBC来处理事务.但是不是直接操作,而是使用Session来操作事务.S

关于spring注解式事务

使用步骤: 步骤一.在spring配置文件中引入<tx:>命名空间<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation

编码式事务

1.编程式事务:编码方式实现事务管理(代码演示为JDBC事务管理) Spring实现编程式事务,依赖于2大类,分别是上篇文章提到的PlatformTransactionManager,与模版类TransactionTemplate(推荐使用).下面分别详细介绍Spring是如何通过该类实现事务管理. 2)PlatformTransactionManager Spring在事务管理时,对事务的处理做了极致的抽象,即PlatformTransactionManager.对事务的操作,简单地来说,只有

seata-分布式事务与seata

分布式事务与 Seata 分布式事务 分布式事务是个现实中很常见的现象,日常的跨行转账就是一个很典型的分布式事务. 现实中,每个银行各自管理各自的账户,在执行跨行转账时,需要确保转出账户扣费正确,转入账户增加正确的金额.在电子渠道上操作看着很简单,其后台需要执行分布式事务的处理流程有很多步骤,如果账户不平,还需要进行人工对账,中间涉及到一系列的制度和机制.这里暂且不涉及电子交易的安全可信的问题,只讨论分布式事务. 转账的数字形式上无非是一系列的电子信号,但是它是用户的财富的事实代表,其转移有法律

CALayer创建和和如何隐藏隐式动画

//修改CALay属性会产生隐式动画 - (void)viewDidLoad { [super viewDidLoad]; // 创建图层 CALayer *layer = [CALayer layer]; layer.backgroundColor = [UIColor blueColor].CGColor; // 设置frame layer.frame = CGRectMake(100, 100, 100, 100); // 添加到控制器view的图层上面 [self.view.layer