C#中回滚TransactionScope的使用方法和原理

TransactionScope只要一个操做失败,它会自动回滚,Complete表示事务完成

 

实事上,一个错误的理解就是Complete()方法是提交事务的,这是错误的,事实上,它的做用的表示本事务完成,它通常放在try{}的结尾处,不用判断前台操做是否成功,若是不成功,它会本身回滚。html

 

 

在.net 1.1的时代,尚未TransactionScope类,所以不少关于事务的处理,都交给了SqlTransaction和SqlConnection,每一个Transaction是基于每一个Connection的。这种设计对于跨越多个程序集或者多个方法的事务行为来讲,不是很是好,须要把事务和数据库链接做为参数传入。数据库

在.net 2.0后,TransactionScope类的出现,大大的简化了事务的设计。示例代码以下:服务器

  1.  
    static void Main(string[] args)
  2.  
    {
  3.  
    using (TransactionScope ts = new TransactionScope())
  4.  
    {
  5.  
    userBLL u = new userBLL();
  6.  
    TeacherBLL t = new TeacherBLL();
  7.  
    u.ADD();
  8.  
    t.ADD();
  9.  
    ts.Complete();
  10.  
    }
  11.  
    }

只须要把须要事务包裹的逻辑块写在using (TransactionScope ts = new TransactionScope())中就能够了。从这种写法能够看出,TransactionScope实现了IDispose接口。除非显示调用ts.Complete()方法。不然,系统不会自动提交这个事务。若是在代码运行退出这个block后,还未调用Complete(),那么事务自动回滚了。在这个事务块中,u.ADD()方法和t.ADD()方法内部都没有用到任何事务类。post

TransactionScope是基于当前线程的,在当前线程中,调用Transaction.Current方法能够看到当前事务的信息。具体关于TransactionScope的使用方法,已经它的成员方法和属性,能够查看 MSDN 。ui

TransactionScope类是能够嵌套使用,若是要嵌套使用,须要在嵌套事务块中指定TransactionScopeOption参数。默认的这个参数为Required。url

该参数的具体含义能够参考http://msdn.microsoft.com/zh-cn/library/system.transactions.transactionscopeoption(v=vs.80).aspxspa

好比下面代码:.net

  1.  
    static void Main(string[] args)
  2.  
    {
  3.  
    using (TransactionScope ts = new TransactionScope())
  4.  
    {
  5.  
    Console.WriteLine(Transaction.Current.TransactionInformation.LocalIdentifier);
  6.  
    userBLL u = new userBLL();
  7.  
    TeacherBLL t = new TeacherBLL();
  8.  
    u.ADD();
  9.  
    using (TransactionScope ts2 = new TransactionScope(TransactionScopeOption.Required))
  10.  
    {
  11.  
    Console.WriteLine(Transaction.Current.TransactionInformation.LocalIdentifier);
  12.  
    t.ADD();
  13.  
    ts2.Complete();
  14.  
    }
  15.  
    ts.Complete();
  16.  
    }
  17.  
    }

当嵌套类的TransactionScope的TransactionScopeOption为Required的时候,则能够看到以下结果,他们的事务的ID都是同一个。而且,只有当2个TransactionScope都complete的时候才能算真正成功。线程



ED8FDA3E241D48B0A90F30A5AC8A9A59

若是把TransactionScopeOption设为RequiresNew,则嵌套的事务块和外层的事务块各自独立,互不影响。设计

  1.  
    static void Main(string[] args)
  2.  
    {
  3.  
    using (TransactionScope ts = new TransactionScope())
  4.  
    {
  5.  
    Console.WriteLine(Transaction.Current.TransactionInformation.LocalIdentifier);
  6.  
    userBLL u = new userBLL();
  7.  
    TeacherBLL t = new TeacherBLL();
  8.  
    u.ADD();
  9.  
    using (TransactionScope ts2 = new TransactionScope(TransactionScopeOption.RequiresNew))
  10.  
    {
  11.  
    Console.WriteLine(Transaction.Current.TransactionInformation.LocalIdentifier);
  12.  
    t.ADD();
  13.  
    ts2.Complete();
  14.  
    }
  15.  
    ts.Complete();
  16.  
    }
  17.  
    }

22D29B0134CD4993B629F085EEBF63D9

能够看到,他们的事务id是不同的。

 

 

TransactionScopeOption的属性值:

 

对于多个不一样服务器之间的数据库操做,TransactionScope依赖DTC(Distributed Transaction Coordinator)服务完成事务一致性。

可是对于单一服务器数据,TransactionScope的机制则比较复杂。主要用的的是线程静态特性。线程静态特性ThreadStaticAttribute让CLR知道,它标记的静态字段的存取是依赖当前线程,而独立于其余线程的。既然存储在线程静态字段中的数据只对存储该数据的同一线程中所运行的代码可见,那么,可以使用此类字段将其余数据从一个方法传递到该第一个方法所调用的其余方法,并且彻底不用担忧其余线程会破坏它的工做。TransactionScope 会将当前的 Transaction 存储到线程静态字段中。当稍后实例化 SqlCommand 时(在此 TransactionScope 从线程局部存储中删除以前),该 SqlCommand 会检查线程静态字段以查找现有 Transaction,若是存在则列入该 Transaction 中。经过这种方式,TransactionScope 和 SqlCommand 可以协同工做,从而开发人员没必要将 Transaction 显示传递给 SqlCommand 对象。实际上,TransactionScope 和 SqlCommand 所使用的机制很是复杂。

相关文章
相关标签/搜索