Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 485|回复: 0

领域模型中分散的事务如何集中统一处理(C#解决方案)

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-5-22 10:24:47 | 显示全部楼层 |阅读模式

    开篇

    什么是事务,事务的应用场景

    做项目时,经常会遇到一些需求,比如注册用户时,要求同时存入用户的基本信息和初始化该用户的帐户,如果在这两个环节中的任何一个地方出错,则要求回滚所有操作,这就是事务,它的主要目的是为了数据的完整性,即要么全盘成功,要么全盘失败,大家都穿一条裤衩。

    今天我要说的复杂事务

    事务的概念很简单,应用起来也很方便,当然可以在存储过程中直接实现事务保证数据的完整性,但是我一般不会这样做,因为我基本把数据库就当做一个数据仓库而已,它是一个容器,没有其他逻辑,逻辑都放领域层来处理,因为这不是我们今天的主要话题,所以就不多讲了。回到正题,那么我们要在C#中实现事务是怎么实现的呢,很简单,直接调用Connection的BeginTransaction方法即可,我们拿ADO.Net中的SqlServer举例,完整的应用示例如下:

    以上代码两Usr表中插入两条数据,要求这两条数据必须都成功插入,否则回滚,逻辑很简单。

    更好的方式

    上面的代码没什么问题,但是如果我们每个地方都这样写,那的确很繁琐,所以出来了很多ORM框架来辅助我们,再看一下EntityFramework是怎么实现事务的

    代码:

    using (RetailEntities context = new RetailEntities())
          {
              context.Customers.Add(entity1);
              context.Customers.Add(entity2);
              context.SaveChanges();
          }

    估计大家都用过,没错,它在SaveChanges方法之前,自动为我们开始了一个事务。这样做的好处,不言而喻,比起上面那样做可谓是简洁了许多。但是今天我们不使用EntityFramework,而是使用自己的方式来解决将要面临的问题。

    我实现事务的方式

    看过我博客的朋友有可能会知道,我以前也写过一个ORM框架(XDBFramework),今天我们主要不讲这个框架,但会引用其中的代码来说明问题,下面就上代码,来看在XDBFramework中是怎样实现事务的。

    DataContext类

    DataAccess类,也就是上面的_da

     

    生成的DataContext类

     

    调用代码:

     using (var context = new DataContext())
                {
                    long count = context.Admin.Count();
                    var a = DataContextStatic.Recharge.Count(s => s.State == Convert.ToInt32(1));
                    string passport = "x" + DateTime.Now.Ticks;
                    context.BeginTransaction();
                    try
                    {
                        context.Admin.Insert(new Model_Admin
                                                 {
                                                     Passport = passport,
                                                     Password = "123456",
                                                     AddTime = DateTime.Now
                                                 });
                        context.Admin.Insert(new Model_Admin
                                                 {
                                                     Passport = passport + "_2",
                                                     Password = "123456",
                                                     AddTime = DateTime.Now
                                                 });
                        context.CommitTransaction();
                    }
                    catch
                    {
                        context.RollbackTransaction();
                    }
    
                    
                }
    事务代码

    能这样实现的关键在于DataContext对象拥有一个DataAccess对象,调用各个DataContext上的各个实体操作自身对应表的时候会调用同一个DataAccess对象,也就是同一个connection,同一个trasaction进行数据的检索,插入,更新,删除操作。这样就实现了把多个操作放到一个事务内。

    引出问题

    想象一下这样一种场景,用户在购买一件商品时,既要生成订单,又要扣除其帐户的相应金额,我们假定在生成订单时会生成多个明细,扣除余额时也会有多条明细。

    解决办法:

    1.有一种方式就是建立一个manager类,然后把生成订单和扣除其帐户的相应金额的逻辑写到一个事务放到这个manager中,如果采用这种方式,当然就不会有本文存在了。

    2.这里要以领域模型的思维方式,即什么对象做什么事,以领域模型建模,这里就有两个模型,即用户帐户和订单。

    于是:  

      a.订单实体里有生成订单的方法,这个方法中包含插入订单总览和明细。

      b.帐户这个实体里有扣除余额的方法,这个方法中包含扣除余额和扣除明细

    这样一来,就有好几个需要事务,即:

        1,生成订单和扣除余额

        2,生成订单和明细

        3,扣除余额和扣除明细

     这样问题就来了,它们本身是一个事务,为了模型的完整,我们现在将它们放在了三处。如何在最后将它们合并成一个事务呢,这就是我们今天要解决的问题。

    进入实例

    场景

    工作流大家应该接触过,我现在就拿这个来说,在保存设计图时,我需要保存那些节点和线条的位置和大小等,在这之前如果是一副被修改的流程图我还要清除原来的元素,在这个场景中,有很多操作都要求在一个事务中,比如之前元素的清徐,新节点的保存,新连接线的保存,新注释的保存等。而这里又有很多实体,比如流程图模版,活动节点(用户活动,系统活动),连接线,注释等,拿它们的保存方法来讲都有不同逻辑,甚至在保存方法内也还有事务的存在。

    代码

    流程图的保存方法

    可以看到这里开始了一个大的事务,将各元素的清除和保存都放到了这个事务中。

    以下的删除方法中又包含了事务(以"Transaction(()=>)"开始的地方)

    实现

    总结

    主要思想是为每个线程分配一个DataContext对象,如果发现是同一个线程在开启事务时,判断是否已经开启事务,如是则直接使用已经开启的事务,如否则开启一个新的事务,原理很简单。

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 07:17 , Processed in 0.057238 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表