TransactionScope

.net为我们提供了TransactionScope类来方便实现transaction的操作。

 

代码一:

View Code
 1       using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, tOptions))
2 {
3 /* Perform transactional work here */
4 Add(ConfigurationManager.ConnectionStrings["ConnectionString1"].ConnectionString, Add2SQL());
5 //throw new Exception();
6 scope.Complete();
7 }
8 public void Add(string connectionString, string commandText)
9 {
10 using (var connection = new SqlConnection(connectionString))
11 {
12 using (var command = new SqlCommand(commandText, connection))
13 {
14 command.CommandType = CommandType.Text;
15 connection.Open();
16 try
17 {
18 command.ExecuteNonQuery();
19 }
20 finally
21 {
22 connection.Close();
23 }
24 }
25 }
26 }

   

只要在using结束之间调用TransactionScope.Complete,在using中调用Dispose时就会commit,如果complete方法没能被调用,例如跑出异常使complete被跳过,在Dispose时就会rollback.

 

再来看复杂一点的例子:

代码二:

代码二
 1  public void RootMethod()    {
2 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, tOptions))
3 {
4 /* Perform transactional work here */
5 SomeMethod();
6 Add(ConfigurationManager.ConnectionStrings["ConnectionString1"].ConnectionString, Add1SQL());
7 scope.Complete();
8 }
9 }
10
11 public void SomeMethod()
12 {
13 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, tOptions))
14 {
15 /* Perform transactional work here */
16 Add(ConfigurationManager.ConnectionStrings["ConnectionString1"].ConnectionString, Add2SQL());
17 scope.Complete();
18 }
19 }

  

TransactionScope的嵌套:

TransactionScopeOption默认是Reqeuired,第二个TransactionScope里,发现已经有了ambient transaction,就不再创建新的transaction了,而是使用这个ambient transaction。可以通过Transaction.Current这个static的属性查看到当前的transactionGUID与前一个确实是一样的。当scope.Complete调用后,Current属性取不到transaction了,会抛出异常,但是执行回到RootMethod方法中,在scope.Complete之前,都可以通过Current取到当前的Transaction

 

分布式Transaction:

代码三:

View Code
 1  public void RootMethod()    {
2 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, tOptions))
3 {
4 /* Perform transactional work here */
5 SomeMethod();
6 Add(ConfigurationManager.ConnectionStrings["ConnectionString1"].ConnectionString, Add1SQL());
7 scope.Complete();
8 }
9 }
10
11 public void SomeMethod()
12 {
13 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, tOptions))
14 {
15 /* Perform transactional work here */
16 Add(ConfigurationManager.ConnectionStrings["ConnectionString1"].ConnectionString, Add2SQL());
17 scope.Complete();
18 }
19 }

  

连接两个不同的DB,会用到分布式事务。在第一个Add方法调用后,Current取到的transactionlocal的,Transcation.Current.TransactionInformationDistributedIdentifierGUID是全0LocalIdentifier是有值的。

第二个Add方法调用后,local transaction会升级到分布式事务,需要系统启动MSDTC服务才能支持,否则会抛出异常。

 

代码四:

    

View Code
 1 public void RootMethod()    {
2 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, tOptions))
3 {
4 Console.WriteLine(Transaction.Current.TransactionInformation.LocalIdentifier);
5 /* Perform transactional work here */
6 SomeMethod();
7 Add(ConfigurationManager.ConnectionStrings["ConnectionString1"].ConnectionString, Add1SQL());
8 scope.Complete();
9 }
10 }
11
12 public void SomeMethod()
13 {
14 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew, tOptions))
15 {
16 Console.WriteLine(Transaction.Current.TransactionInformation.LocalIdentifier);
17 /* Perform transactional work here */
18 Add(ConfigurationManager.ConnectionStrings["ConnectionString1"].ConnectionString, Add2SQL());
19 scope.Complete();
20 }
21 }

 

两个TransactionScope中用的同一个DB,但是TransactionScopeOptionRequiresNew,在第二个scope中无论ambient transaction是否存在,都会创建新的transactionGUID是一样的,序号不同。

如果在SomeMethod执行成功,并complete,但是RootMethodAdd失败,SomeMethod中的Add是不会rollback的。

posted @ 2011-08-16 18:03  皮业勇  阅读(1051)  评论(0编辑  收藏  举报