温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C#综合揭秘——细说事务(下)

发布时间:2020-04-11 11:16:23 阅读:821 作者:leslies2 栏目:编程语言
开发者测试专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

目录

一、事务的定义

二、事务管理器

三、在ADO.NET中实现事务

四、隐式事务 TransactionScope

五、在WCF中实现事务

六、嵌套式事务

七、异步事务

六、嵌套式事务

嵌套式事务经常会出现在项目中,但往往容易被大家忽略,下面介绍一下 嵌套式事务的用法:

 1 using (TransactionScope scope1 = new TransactionScope())            
 2 {
 3        ..............               
 4        using (TransactionScope scope2=new TransactionScope(TransactionScopeOption.RequiresNew))
 5        {
 6               ..............
 7               scope2.Complete();   //只完成嵌套式的内部事务,但事务并未正式提交 8        }
 9        scope1.Complete();  //代表完成所有事务,事务正式提交10 }

一 般项目中,大家都只会把事务用在DAL层,用于管理数据的CRUD,但其实在一些操作中,某些数据的操作必须具有一致性。比如在订单管理中,当插入一条 OrderItem时,Order表内的总体价格,商品数量等也会随之改变。很多人把两个表的操作合成一个方法,放在OrderDAL中完成。但其实这样 做违返设计的原则,因为计算Order的总体价格时可能会包含商品优惠、客户等级、客户积分等等业务逻辑,而在DAL层不应该包含任何的业务逻辑存在的, 所以这样操作应该放在业务层完成。这时候,业务层的方法内就需要同时调用OrderItemDAL的AddOrderItem(OrderItem) 方法和OrderDAL的UpdateOrder(Order)方法,为了保证数据的一致性更新,就需要使用嵌套式事务。但这往往容易被开发人员所忽略, 当Order表的更新成功而OrderItem表的插入失败时,系统不能保证数据的同步回滚,那就会造成数据的逻辑性错误。

下面的例子就是为了保证数据一致性更新而使用的嵌套式事务,在使用嵌套式事务的时候要应该注意及其把对象释放,避免做成死锁

 1 namespace DAL
 2 {     
 3      public class OrderDAL
 4      {
 5          public void UpdateOrder(Order order)
 6          {
 7              using (TransactionScope scope = new TransactionScope())
 8              {
 9                   ......         
10                   scope.Complete();
11              }
12          }
13      }
14  
15      public class OrderItemDAL
16      {
17          public void AddOrderItem(OrderItem orderItem)
18          {
19              using (TransactionScope scope = new TransactionScope())
20              {
21                  ......
22                  scope.Complete();
23              }
24          }
25      }
26  }
27 
28 namespace BLL
29 {
30      public class OrderManager
31      {
32          public void AddOrderItem(OrderItem item)
33          {
34              using (TransactionScope scope = new TransactionScope())
35              {
36                  OrderItemDAL orderItemDAL=new OrderItemDAL();
37                  orderItemDAL.AddOrderItem(item);
38                  OrderDAL orderDAL=new OrderDAL();
39                  ........
40                  orderDAL.UpdateOrder(order);
41                  scope.Complete();
42              }
43          }
44      }
45 }

回到目录

七、异步事务

记得在第二节的时候曾经提起过事务类Transaction的方法中包含方法

public DependentTransaction DependentClone(DependentCloneOption)

此方法作用是克隆当前的事务,它在多线程调用同一事务的情况下使用经常使用。其中DependentCloneOption包含有两个选项:

一为BlockCommitUntilComplete,这表示在依赖事务未完成前,事务将处于阻塞状态,只有在所有依赖事务完成后,事务才能执行提交;

二为RollbackInNotComplete,这表示依赖事务必须在事务完成前调用Complete(),否则事务会被视为失败。

在 普通情况下,事务都会通过Transaction.Current 来获取,但此方法只能获取当前线程下的事务对象,在异步方法当中,这只会返回一个空值 null 。此时就需要使用DependentClone 方法获取依赖事务对象 DependentTransaction ,再把此对象作为参数传递到回调函数中。

 1      class Program
 2      {
 3          static void Main(string[] args)
 4          {
 5              Method();
 6              Console.ReadKey();
 7          }
 8  
 9          static void Method()
10          {
11              using (TransactionScope scope = new TransactionScope())
12              {
13                  ShowMessage("Main Thread");
14  
15                  //获取一个依赖事务,把依赖事务作为回调参数传到回调函数中16                  DependentTransaction dependentTransaction=
17                     Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
18                  ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncThread), dependentTransaction);
19                  ........
20                  scope.Complete(); //完成主线程事务,在依赖事务完成前,事务提交将处于阻塞状态
21              }
22          }
23  
24          static void AsyncThread(object transaction)
25          {
26              //获取依赖事务,利用TransactionScope(Transaction)构造函数生成隐式事务27              DependentTransaction dependentTransaction = (DependentTransaction)transaction;
28              using (TransactionScope scope = new TransactionScope(dependentTransaction))
29              {
30                  ShowMessage("AsyncThread");
31                  ..........
32                  scope.Complete();  //完成异步事务33              }
34              //完成依赖事务35              dependentTransaction.Complete();
36          }
37  
38          static void ShowMessage(string data)
39          {
40              if (Transaction.Current != null)
41              {
42                  Transaction transaction = Transaction.Current;
43                  string info = string.Format("{0}:{1}\nTransaction:\n  DistributedIndentifier:{2} \n  LocalIndentifier:{3}\n",
44                      data,Thread.CurrentThread.ManagedThreadId.ToString(),
45                      transaction.TransactionInformation.DistributedIdentifier,
46                      transaction.TransactionInformation.LocalIdentifier);
47                  Console.WriteLine(info);
48              }
49          }
50      }

首 先在主线程中利用 Transaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete) 方法生成一个依赖事务,注意方法使用了BlockCommitUntilComplete的方式生成,即事务将在所有依赖事务使用Complete()后 才能执行提交。

然后利用ThreadPool.QueueUserWorkItem(WaitCallback,Object)方法把依赖事务作为回调参数传递到回调函数中。

最后在回调函数中使用TransactionScope(transaction)构造函数生成对象,这代表把参数transaction作为当前的环境事务对象。观察下面的运行结果,两个线程中的事务都是同一个事务。

C#综合揭秘——细说事务(下)

结束语

事务是在多个层次都会使用到的,但很多项目当中往往会忽略了这一点而只在数据层使用,在大型的系统当中这样可能会影响到系统的一致性。特别是在分布式系统当中,操作往往同时存在于多个不同的系统当中,事务的处理更显示出其重要性。

希望本篇文章对相关的开发人员有所帮助。对JAVA与.NET开发有兴趣的朋友欢迎加入QQ群:162338858 C#综合揭秘——细说事务(下)

回到目录

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI

开发者交流群×