现在的位置: 首页 > 综合 > 正文

C#Base——System.Transaction(2.0事务)

2012年09月29日 ⁄ 综合 ⁄ 共 4768字 ⁄ 字号 评论关闭

之所以标题叫system.Transaction而不直接叫事务, 是因为该文主要是对2.0以后的事务操作进行描述,不涉及ADO.NET的事务和事务操作的基本知识

(一)

从2.0开始,C# 中就可以使用System.Transaction进行事务操作了,相比与原始的ADO/ADO.NET提供的事务操作,2.0以来的新的事务操作主要在分布式事务和环境事务上进行了优化和升级

(二) 分布式事务(Distributed Transaction)

分布式事务是指事务可以进行传递而不仅仅是在当前类中进行事务管理,这种传递不仅仅是跨实例之间进行传递的,更可以是跨线程传递,甚至WCF中在服务和客户端进行传递(System.Transaction是可序列化的),来实现协同的事务操作,Windows下主要通过DTC(分布式事务协调器)来进行管理

(三)依赖事务(DependentTransaction)

实现分布式事务主要是靠“依赖事务”(DependentTransaction)来实现的,继承自Transaction的类一般都可以调用DependentClone来创建当前事务的依赖事务,然后将依赖事务传递给需要的线程,在子线程中,可以使用这个传递过来的DependTransaction来进行Complete和Rollback。

   1.使用DependentClone来创建依赖事务

   在创建依赖事务时,有两个可选参数:DependentCloneOption.BlockCommitUntilComplete和DependentCloneOption.RollbackIfNotComplete

   其中,BlockCommitUntilComplete是指:当主线程(根事务root Transaction所在的线程)中,根事务进行提交(commit)时(包括transactionScope在using结束时自动提交(注意:不是complete,TransactionScope的complete只是设置了事务成功标示)),会判断其产生的依赖事务是否已经调用complete/rollback,如果有线程中的依赖事务没有complete/rollback,则主线程中的根事务会阻塞(block)等待所有依赖事务都complete/rollback后才会complete(如果是rollback,transactionScope会激发事务已关闭的异常)。

  RollbackIfNotComplete是指在主线程中的根事务到达complete时,如果依赖事务还有没有结束(complete/rollback)的,则整个事务回滚。

  注意:对于环境事务(TransactionScope)在子线程中,需要将依赖事务赋值给环境事务,然后使用环境事务对依赖事务进行控制,如:(例子中使用的是自定义的资源管理,便于测试)

 1         static void ThreadMethod(object dependentTx)
2 {
3 DependentTransaction dtx = dependentTx as DependentTransaction;
4
5 if (dtx != null)
6 {
7 Transaction.Current = dtx;
8 }
9 try
10 {
11 using (var scope = new TransactionScope())
12 {
13 Transaction.Current.TransactionCompleted +=
14 TransactionCompleted;
15
16 Utilities.DisplayTransactionInformation("Thread TX",
17 Transaction.Current.TransactionInformation);
18
19 intVal.Value = 64;
20
21 scope.Complete();
22
23 Console.WriteLine("Commit");
24 }
25 }
26 catch (TransactionAbortedException ex)
27 {
28 Console.WriteLine("ThreadMethod—Transaction was aborted, {0}",
29 ex.Message);
30 }
31 finally
32 {
33 dtx.Complete();
34 }
35 }

第7行将传递过来的依赖事务赋值给环境事务,所以第11-24行才能使用环境事务进行事务控制,环境事务的特点是:如果不显式调用complete(21行),则整个事务会回滚。可以看到第33行,对依赖事务又进行了一次complete,这是因为,根事务不把环境事务的结束(complete/rollback)作为依赖事务的结束,必须显式的调用依赖事务的complete/rollback方法后,根事务才能捕获的依赖事务的处理结果,也就是说,如果将33行注释掉,如果我使用BlockCommitUntilComplete,则整个事务将一直无法提交,如果使用RollbackIfNotComplete,则整个事务将一直回滚。

这是就会有疑问:21行和33行两个事务结束的结果之间到底对整个事务的处理有什么影响,经过测试,得出如下结论:

其实也就是只有在两个事务都为commit状态下,其处理结果才被认为是commit,符合我们的一般认识。这样,在书写使用环境事务的依赖事务时,可以一直将依赖事务的处理结果置为complete,只需按习惯写法,对环境事务的处理结果进行控制就行了

 

(四)环境事务

上面其实已经提到了环境事务,环境事务的最大特点是在一些支持环境事务的资源管理器(ResourceManager)中,使用环境事务可以不进行手工注册,如:在使用普通事务,如commitableTransaction时,如果想在ADO.NET中使用该可提交事务,就必须将该事务注册到ADO.NET的连接(connection)中:Connection.EnlistTransaction(tx)//tx是使用的事务的实例,而且需要显示的对事务进行commit(当然,在不可手工提交的事务中没有commit),在发生异常时进行rollback,环境事务在设计的时候继承了IDispose接口,在Dispose中进行了commit/rollback的判断,所以只需使用using,可节省一部分代码,而且,在创建环境事务时可以选择使用以前的环境事务或新增环境事务,比直接传递事务要方便。

上面大概说明了一下环境事务的优点,下面介绍一下环境事务的使用方法

1.创建/实例化环境事务

环境事务在创建时有一个可选参数:TransactionScopeOpition,常用取值为Required,RequiresNew。区别是:
Required:如果已经存在一个环境事务,则新建的环境事务使用已有的环境事务,只有在所有引用该环境事务的实例都complete后,环境事务才被认为是complete
               如果没有已存在的环境事务,则新增一个环境事务

RequiresNew:不管是否已经存在环境事务,都新增一个环境事务实例,且这个实例和其他的环境事务实例不进行任何管理,相互独立

环境事务新增时默认的参数是Required

当前的环境事务可以使用Transaction.Current来GET/SET

环境事务可以进行嵌套,嵌套后两个环境事务实例的处理结果由TransactionScopeOpition的取值决定

环境事务的作用域中,如果没有显示调用complete,则环境事务将会回滚

(五)实例

这个实例包含了环境事务和依赖事务的用法,其中Transactional是一个自定义资源管理器,大家把它和数据库的资源管理器一样理解即可,暂时不必深究,Utilities是一个输出事务信息的公共类,只有Display的功能,所以具体代码就也不贴出来了

 1 class Program
2 {
3 static Transactional<int> intVal = new Transactional<int>(1);
4
5 static void Main()
6 {
7
8
9 Console.WriteLine("start--" + intVal.Value);
10 try
11 {
12 using (var scope = new TransactionScope())
13 {
14 Transaction.Current.TransactionCompleted +=
15 TransactionCompleted;
16
17 Utilities.DisplayTransactionInformation("Main thread TX",
18 Transaction.Current.TransactionInformation);
19 new Thread(ThreadMethod).Start(Transaction.Current.DependentClone(DependentCloneOption.RollbackIfNotComplete));
20
21 scope.Complete();
22 }
23 }
24 catch (TransactionAbortedException ex)
25 {
26 Console.WriteLine("Main—Transaction was aborted, {0}",
27 ex.Message);
28 }
29
30
31
32 Console.ReadLine();
33 Console.WriteLine("at last--" + intVal.Value);
34 Console.ReadLine();
35 }
36
37 static void TransactionCompleted(object sender, TransactionEventArgs e)
38 {
39 Utilities.DisplayTransactionInformation("TX completed",
40 e.Transaction.TransactionInformation);
41 }
42
43 static void ThreadMethod(object dependentTx)
44 {
45 DependentTransaction dtx = dependentTx as DependentTransaction;
46
47
48 if (dtx != null)
49 {
50 Transaction.Current = dtx;
51 }
52
53 try
54 {
55 using (var scope = new TransactionScope())
56 {
57 Transaction.Current.TransactionCompleted +=
58 TransactionCompleted;
59
60 Utilities.DisplayTransactionInformation("Thread TX",
61 Transaction.Current.TransactionInformation);
62
63 intVal.Value = 64;
64
65 //Thread.Sleep(1000000000);
66
67 scope.Complete();
68
69 Console.WriteLine("Commit");
70 }
71 }
72 catch (TransactionAbortedException ex)
73 {
74 Console.WriteLine("ThreadMethod—Transaction was aborted, {0}",
75 ex.Message);
76 }
77 finally
78 {
79 dtx.Complete();
80 }
81 }
82
83 }

抱歉!评论已关闭.