zoukankan      html  css  js  c++  java
  • .Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?

    本文将通过场景例子演示,来通俗易懂的讲解在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码。

    用一句话贯穿全文就是:通过委托来让TransactionScope的编码实现更直观,并不是讲述TransactionScope的其它如分布式、ACID等场景应用及解决方案。

    通过一系列优化最终达到两个效果,1.让不了解TransactionScope的童鞋通过代码块TransactionScope来控制事务,2.让了解TransactionScope的童鞋简单概述本实例的委托思想抛砖引玉来优化TransactionScope的编码写法。

    本文需要的知识点:1. Action委托  2. 分布式事务TransactionScope(不懂不要紧,文中会通过示例一和示例二简单讲解这是啥,为啥要用)

    ----------------------

     .Net Web开发技术栈

    .Net高级进阶,教你如何构建企业模型数据拦截层,动态控制字段验证

    .Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?

    web安全:通俗易懂,以实例讲述破解网站的原理及如何进行防护!如何让网站变得更安全。

    web安全:QQ号快速登录漏洞及被盗原理

    .Net,Dll扫盲篇,如何在VS中调试已经编译好的dll?

    ----------------------

    示例一和示例二,主要是来讲解 TransactionScope 是什么,为什么要用TransactionScope。
    示例三(重要)则是优化写法,增加代码的灵活性和可读性。

    【示例一】

    现在,你要写个入库接口,大致意思就是: 勾选一条商品,然后写上数量,点击入库按钮,将会产生一条入库记录,同时  这个商品的所对应的  库存数量 也会 更新。
    因为涉及到库存,所以要用事务来保证数据安全。

    StorageTask:入库作业表,存写入库记录

    GoodsInventory:商品库存表, 里面放的是  不同商品的 详细介绍、数量等信息

    那么我们的实现  ,  可能是 这样的 , 如图:

    上图的代码,我们主要是先看  商品入库操作  GoodsInventoryOperate  这个Dal方法,放图:

     

    上面的这是一个Dal方法,事务写法很大众,很常规,代码没毛病。

    【示例二】

    好,现在,我们的业务要求要改一下,改成这样的:

     勾选了一条商品,输入该条商品的入库数量,然后又勾选了一条原材料,输入该原材料的入库数量,最终点击入库按钮,要  产生 商品的入库记录和原材料的入库记录, 还要 分别修改 所对应的 商品库存表和原材料库存表 的 库存数量

    那么,我们就要修改下这个接口,首先,参数由原来的   单行的参数  改为  集合形式的 参数,

    那么我们的接口代码也随之修改,如下图:

    然后我们在看看 这个入库操作方法 InventoryOperate

    我们来对比下,我们把之前的 商品入库操作  GoodsInventoryOperate 方法 给改成了  入库操作方法 InventoryOperate 。

    实际上,入库操作方法 InventoryOperate =  商品入库操作  +  原材料入库操作 ,但是因为 业务的更改,让我们不得不把 原本 Dal层中的两个方法代码 给 复制粘贴到一起,形成第三个方法,也就是入库操作方法 InventoryOperate 。

    那么,有没有一种写法,能让我们 更简单更方便  不用每次复制粘贴代码形式 来实现 事务的编写?

    有!

    TransactionScope:

      在早期.net时代,如果想使用事务,就用SqlTransaction来实现,而每个SqlTransaction都会用同一个SqlConnection连接对象。
      如果逻辑简单还好说,如果逻辑稍微复杂的话,想用多个Dal方法来共同组合一个事务的话,就非常费脑筋的,就像上文这样演变的 第一版 和 第二版。
      为此,在.Net2.0时代,TransactionScope诞生了,微软官方描述:代码块事务,还有一个别称:分布式事务。
      它实现了IDisposable接口,可以把它被实例化开始到被Dispose掉之间的代码作为一个事务,也就是它的存在,最终让你的代码块所嵌套在其中多个DAL方法变成“一个方法”

    那么,当我们使用它以后,我们就可以这样编写:

    【示例三】

     现在,大家对 TransactionScope 有了基本的印象,那么现在考虑到代码的可读性和灵活性,我将要对当前风格再次改写,通过委托的形式让代码结构层次更加分明。

     1         /// <summary>
     2         /// 事务语句统一执行
     3         /// </summary>
     4         /// <param name="ac">委托</param>
     5         /// <returns></returns>
     6         public static bool TransactionExecute(Action ac)
     7         {
     8             try
     9             {
    10                 using (TransactionScope ts = new TransactionScope())
    11                 {
    12                     ac.Invoke();
    13                     ts.Complete();
    14                 }
    15                 return true;
    16             }
    17             catch
    18             {
    19                 return false;
    20             }
    21         }    

    然后,我们的接口方法的编码变成了这样:

     1         /// <summary>
     2         /// 商品仓库的入库作业操作
     3         /// </summary>
     4         /// <param name="iData">入库数据集合</param>
     5         /// <returns></returns>
     6         public string WarehouseGoodsOperate(List<InboundModel> iData)
     7         {
     8             Action ac = () => { };//声明一个委托
     9             foreach (InboundModel item in iData)
    10             {
    11                 if (item.type == "商品")
    12                 {
    13                     ac += () =>
    14                     {
    15                         IServices.Insert(item);
    16                         IServices.UpdateGoods(item);
    17                     };
    18                 }
    19                 if (item.type == "原材料")
    20                 {
    21                     ac += () =>
    22                     {
    23                         IServices.Insert(item);
    24                         IServices.UpdateInventory(item);
    25                     };
    26                 }
    27             }
    28             if (IServices.TransactionExecute(ac))
    29             {
    30                 return "成功";
    31             }
    32             return "失败";
    33         } 

     通过上面这样的写法,最终让代码风格更干净,同时在 事务的 处理上更灵活方便, 我们只需要把想要执行的 方法 让 ac 给包进去, 最后在调用 TransactionExecute 统一执行。

     基于自己的场景可以定制自己的TransactionExecute,本文着重指出利用委托来优化该情况下的编码思想,至于TransactionExecute,这里只是做个简单的科普,其中有更多可挖掘的地方,感兴趣的童鞋可以自行百度。

     当然,采用这种委托写法,需要注意一点:

    因为传递的是引用,并且用用到了lambda,导致了闭包,最终在Invoke时在匿名类中会用同一引用。

    那么,怎样解决这样情况?
    逐个逐个的赋值,或者用反射?
    不用,我们可以通过继承 ICloneable 接口,然后通过浅复制的方式实现Clone方法(浅复制拷贝时,string会创建新的实例,如果尚有除string之外的引用类型还需深拷贝)。

        class SysUser : ICloneable
        {
            public object Clone()
            {
                return this.MemberwiseClone(); 
            }
        }

    最后,我们就可以这样:

    让正确的程序更快比让快速的程序正确要容易的多

    我喜欢和我一样的人交朋友,不被环境影响,自己是自己的老师,欢迎加群 .Net web交流群, QQ群:166843154 欲望与挣扎

    作者:小曾
    出处:http://www.cnblogs.com/1996V/p/7798111.html  欢迎转载,但任何转载必须保留完整文章,在显要地方显示署名以及原文链接。如您有任何疑问或者授权方面的协商,请给我留言
    .Net交流群, QQ群:166843154 欲望与挣扎 
  • 相关阅读:
    程灵素:我走过山的时候山不说话
    编译原理自学计划
    由一个虚构的例子谈谈中小型研发型项目的技术管理及成本控制(全文)
    用3种IDE导入Linux 2.26 内核源码
    Web风行者的设计方案与计划
    使用pyste自动生成c++类的python wrapper
    让log4cpp日志文件超过2G(Linux下)的方法
    python绑定c++程序
    网络风行者(KSpider)的规则体系结构
    检测您的浏览器是否支持 HTML5 视频方法
  • 原文地址:https://www.cnblogs.com/1996V/p/7798111.html
Copyright © 2011-2022 走看看