DataRabbit 轻量的数据访问框架(08) -- TransactionScope

(完全限定类名:DataRabbit.Application.TransactionScope)

  前面讲了多种访问器,并且这些访问器都继承了ITransactionAccesser接口。我们已经知道,ITransactionAccesser的含义在于:访问器对象即可以工作于一个事务(Transaction)上下文中,也可以在脱离事务的环境中工作。前面举的所有示例中都没有涉及到事务,本文我们将介绍在DataRabbit中如何使用事务。
    如果你够细心的话,一定还记得,当我们从DataRabbit的入口处IDataAccesser获取各种访问器实例时,都需要传递一个类型为 IDbTransaction的参数,用于构建一个在指定事务上下文中工作的访问器,如果需要非事务相关的访问器对象,这个参数就传入null。

  下面我们举个非常简单的事务访问的例子,假设某个业务逻辑要求我们在Update某个student的Age的时候,必须在Book表中插入一条相关记录,这是一个事务性的动作。通过我们已经掌握的DataRabbit知识,我们可以这样达成目标:
            IDbTransaction trans = null ;
            try
            {
                trans = dataAccesser.DataElementFactory.NewConnection().BeginTransaction();
                IOrmAccesser<Student> stuOrmAccesser = dataAccesser.GetOrmAccesser<Student>(trans);
                IOrmAccesser<Book> bookOrmAccesser = dataAccesser.GetOrmAccesser<Book>(trans);

                //更新Student
                Student stu = new Student();
                stu.ID = 33;
                stu.Age = 28;
                stuOrmAccesser.Update(stu);

                //插入Book
                Book book = new Book();
                book.ID = 9;
                book.StudentID = stu.ID;
                bookOrmAccesser.Insert(book);

                trans.Commit();
                trans.Dispose();
            }
            catch
            {
                if (trans != null)
                {
                    trans.Rollback();
                    trans.Dispose();
                }
            }
  这样做未免有点繁琐,而且调用者要在代码中直接使用IDbTransaction这样比较底层的构件。DataRabbit给出了TransactionScope来解决这个问题。

  TransactionScope,表示一个事务的范围,我们可以从TransactionScope中获取前述的所有访问器实例,并且从中获取的访问器都是基于事务的(访问器的生命期将随事务的结束而结束)。TransactionScope的类图如下所示:
(完全限定类名:DataRabbit.Application.TransactionScope

  前面讲了多种访问器,并且这些访问器都继承了ITransactionAccesser接口。我们已经知道,ITransactionAccesser的含义在于:访问器对象即可以工作于一个事务(Transaction)上下文中,也可以在脱离事务的环境中工作。前面举的所有示例中都没有涉及到事务,本文我们将介绍在DataRabbit中如何使用事务。
  如果你够细心的话,一定还记得,当我们从DataRabbit的入口处IDataAccesser获取各种访问器实例时,都需要传递一个类型为IDbTransaction的参数,用于构建一个在指定事务上下文中工作的访问器,如果需要非事务相关的访问器对象,这个参数就传入null。

  下面我们举个非常简单的事务访问的例子,假设某个业务逻辑要求我们在Update某个student的Age的时候,必须在Book表中插入一条相关记录,这是一个事务性的动作。通过我们已经掌握的DataRabbit知识,我们可以这样达成目标:
            IDbTransaction trans =
null ;
           
try
            {
                trans
= dataAccesser.DataElementFactory.NewConnection().BeginTransaction();
                IOrmAccesser
<Student> stuOrmAccesser = dataAccesser.GetOrmAccesser<Student>(trans);
                IOrmAccesser
<Book> bookOrmAccesser = dataAccesser.GetOrmAccesser<Book>(trans);

               
//更新Student
                Student stu =
new Student();
                stu.ID
=
33;
                stu.Age
=
28;
                stuOrmAccesser.Update(stu);

               
//插入Book
                Book book =
new Book();
                book.ID
=
9;
                book.StudentID
= stu.ID;
                bookOrmAccesser.Insert(book);

                trans.Commit();
                trans.Dispose();
            }
           
catch
            {
               
if (trans !=
null)
                {
                    trans.Rollback();
                    trans.Dispose();
                }
            }

  这样做未免有点繁琐,而且调用者要在代码中直接使用IDbTransaction这样比较底层的构件。DataRabbit给出了TransactionScope来解决这个问题。

  TransactionScope,表示一个事务的范围,我们可以从TransactionScope中获取前述的所有访问器实例,并且从中获取的访问器都是基于事务的(访问器的生命期将随事务的结束而结束)。TransactionScope的类图如下所示:

  首先,我们看到了一些以“New”打头的方法,这些方法用于创建各种基于事务的访问器对象。
  TransactionScope会在构造函数中启动事务,所以我们只有在需要事务的地方才构建TransactionScope实例。TransactionScope实例通常在Business Flow子层中创建。另外,TransactionScope支持两种使用模式:



(1)自动模式:使用using块 ,将在异常发生时,自动回滚事务。
(2)手动模式:不使用using块,可根据业务需要手动回滚事务(调用TransactionScope的Rollback方法),更具灵活性。
 
  我们可以通过DataRabbit.Application.TransactionScopeFactory来获得TransactionScope对象。现在我们来看看使用TransactionScope如何实现上面的示例功能:
            //transactionScopeFactory通常以singleton模式使用
            TransactionScopeFactory transactionScopeFactory = new TransactionScopeFactory(dataAccesser); //如何获取dataAccesser对象,可参见 序

            using (TransactionScope scope = transactionScopeFactory.NewTransactionScope())             
            {             
                IOrmAccesser<Student> stuOrmAccesser = scope.NewOrmAccesser<Student>();
                IOrmAccesser<Book> bookOrmAccesser = scope.NewOrmAccesser<Book>();

                //更新Student
                Student stu = new Student();
                stu.ID = 33;
                stu.Age = 28;
                stuOrmAccesser.Update(stu);

                //插入Book
                Book book = new Book();
                book.ID = 9;
                book.StudentID = stu.ID;
                bookOrmAccesser.Insert(book);

                scope.Commit(); //提交事务,别忘了这句           
            }

  上述代码如果在Update或Insert的时候抛出异常,事务将会自动回滚,这是在TransactionScope的Dispose方法中做到的。使用TransactionScope,我们将不用在直接接触IDbTransaction这样比较底层的元素,而且代码也显得更加精练。

原文出处:http://www.cnblogs.com/zhuweisky/
金鳞岂是池中物,一遇风云便化龙