TransactionScope
.net为我们提供了TransactionScope类来方便实现transaction的操作。
代码一:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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.
再来看复杂一点的例子:
代码二:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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的属性查看到当前的transaction的GUID与前一个确实是一样的。当scope.Complete调用后,Current属性取不到transaction了,会抛出异常,但是执行回到RootMethod方法中,在scope.Complete之前,都可以通过Current取到当前的Transaction
分布式Transaction:
代码三:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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取到的transaction是local的,Transcation.Current.TransactionInformation的DistributedIdentifier的GUID是全0,LocalIdentifier是有值的。
第二个Add方法调用后,local transaction会升级到分布式事务,需要系统启动MSDTC服务才能支持,否则会抛出异常。
代码四:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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,但是TransactionScopeOption是RequiresNew,在第二个scope中无论ambient transaction是否存在,都会创建新的transaction,GUID是一样的,序号不同。
如果在SomeMethod执行成功,并complete,但是RootMethod的Add失败,SomeMethod中的Add是不会rollback的。