• TransactionScope的使用


    本文导读:在实际开发工作中,执行一个事件,然后调用另一接口插入数据,如果处理逻辑出现异常,那么之前插入的数据将成为垃圾数据,我们所希望的是能够在整个这个方法定义为一个事务,TransactionScope 类提供一个简单方法,通过这一方法,您不必与事务本身交互,即可将代码块标记为参与某个事务。TransactionScope对象创建了一个事务,同时将该事务设置给Transaction类的Current属性。

    一、TransactionScope的优点


    1、使用起来比较方便.TransactionScope可以实现隐式的事务,使你可以在写数据访问层代码的时候不用考虑到事务,而在业务层的控制事务.

    2、可以实现分布式事务,比如跨库或MSMQ.

    二、TransactionScope缺点

    1、性价比不高.比如,你只是在"Scope"里控制一个库的事务.用"TransactionScope"就有点浪费了.
    2、一般情况下只要你使用"TransactionScope",都要配置MSDTC,要配防火墙,要开139端口.这个端口不可以更改

    三、如果你不得不用分布式事务,那也得琢磨琢磨

    1.这步操作一定得在事务当中吗?这步操作如果没完成或者失败了,值得回滚整个事务吗?难道没有优雅的补偿措施或者容错措施?

    2.分布式事务涉及到的点,必须的这么多?必须得实时的操作这一大串?不能通过通知类操作去精简掉某些点?

    3.在发起分布式事务之后,你是不是做了事务无关的操作,尽管这些操作跟事务无关?(如,读取数据、计算、等用户返回消息、等其他模块的调用返回等等)要知道事务应该尽快结束。

    4.你没有把一些读操作也算在事务里面了吧?这是很容易犯的错误,你在事务中Enlist了一个select 操作。

    5.你的操作,某些步骤可以等全部操作完成之后再执行.这类操作具有明显的通知类特点。通知类操作是说,我给你一个通知,并且我保证通知到了你;你必须吃下这个通知,并且保证处理成功,但是你不必我一通知你你就处理。这样的操作很明显可以用另外一个任务去搞。

    四、使用分布式事务注意如下几点

    1:确保参与事务的machine开启了分布式事务支持;

    2:如果machine开启了防火墙,需要设置msdtc进程为例外;

    3:参与事务的machine不能跨域(如果跨域,目前微软还没有确切的解决方案);

    4:多数据库时才使用分布式事务,如果是同一个数据库,最好使用SqlTransaction.

    五、TransactionScope事务级别

    在TransactionScope中默认的事务级别是Serializable,即在事务过程中,完全性锁表。别的进程不能查询,修改,新增,删除。这样会导致效率大大降低,虽然数据完整性很高。通常我们不需要那么高的数据完整性。所以需要修改默认的事务级别:

    所有的事务级别如下


    Chaos

    无法改写隔离级别更高的事务中的挂起的更改。


    ReadCommitted

    不可以在事务期间读取可变数据,但是可以修改它。


    ReadUncommitted

    可以在事务期间读取和修改可变数据。


    RepeatableRead

    可以在事务期间读取可变数据,但是不可以修改。可以在事务期间添加新数据。


    Serializable

    可以在事务期间读取可变数据,但是不可以修改,也不可以添加任何新数据。


    Snapshot

    可以读取可变数据。在事务修改数据之前,它验证在它最初读取数据之后另一个事务是否更改过这些数据。如果数据已被更新,则会引发错误。这样使事务可获取先前提交的数据值。

    在尝试提升以此隔离级别创建的事务时,将引发一个 InvalidOperationException,并产生错误信息“Transactions with IsolationLevel Snapshot cannot be promoted”(无法提升具有 IsolationLevel 快照的事务)。


    Unspecified

    正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。如果设置了此值,则会引发异常。

    六、在C#中使用TransactionScope类(分布式事务),则须注意如下事项

    1、在项目中引用using System.Transactions命名空间(先要在添加net组件的引用);

    2、对MSDTC组件设置:

    在控制面板--->管理工具--->服务 中,开启Distributed Transaction Coordinator 服务。


    a、控制面板->管理工具->组件服务->计算机->我的电脑->右键->属性
    b、选择MSDTC页, 确认"使用本地协调器"
    c、点击下方"安全配置"按钮
     

    d、勾选: "允许网络DTC访问","允许远程客户端","允许入站","允许出站","不要求进行身份验证".
    e、对于数据库服务器端, 可选择"要求对呼叫方验证"
    f、勾选:"启用事务Internet协议(TIP)事务"。
    g、在双方防火墙中增加MSDTC.exe例外
    可用命令行: netsh firewall set allowedprogram %windir%/system32/msdtc.exe MSDTC enable

    3、重启IIS服务器。

    注意:

    我们只要确保数据库的打开操作是在事务范围内打开就行了。这样就可以做到事务的正确操作。

    如果WEB服务器和数据库是在同一台服务器上,TransactionScope使用的是本地事务,这时不需要配置MSDTC。

    如果WEB服务器和数据库不在同一台服务器上,TransactionScope会自动提升事务级别为分布式事务,这时就需要配置MSDTC。

    七、TransactionScope实例

     
    C# 代码   复制
            /**//// <summary>
            /// 发送消息
             /// </summary>
            /// <param name="sendUserId"></param>
            /// <param name="toUser">格式7FFA3AF2-E74B-4174-8403-5010C53E49A7|userName,7FFA3AF2-E74B-4174-8403-5010C53E49A7|userName</param>
            /// <param name="content"></param>
            /// <param name="sendedStatus">表示已送</param>
            /// <returns></returns>
            public static int sendMessage(string sendUserId, string toUser, string content, string sendedStatus)
            {           
                int receiveCount = 0;
                TransactionOptions transactionOption = new TransactionOptions();
    
                //设置事务隔离级别
                transactionOption.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
    
                // 设置事务超时时间为60秒
                transactionOption.Timeout = new TimeSpan(0, 0, 60);
    
                using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, transactionOption))
                {
                    try
                    {
                        //在这里实现事务性工作
         //发送消息
                        insertMessage(sendUserId, toUser, content, sendedStatus);
    
         //在接收信息表中插入记录
                        receiveCount += insertReceiveMessage(userids[0], sendUserId, content, "0");
                       
                        // 没有错误,提交事务
                        scope.Complete();
                    }
                    catch (Exception ex) {
                        throw new Exception("发送信息异常,原因:"+ex.Message);
                    }finally{
                        //释放资源
                        scope.Dispose();
                      }                               
                }
                return receiveCount;
            }
    

          一说到事务大家都会想到在存储过程中使用事务,这样可以保证多表操作时的数据一致性。但是三层架构中D层的方法很多都是针对单表操作的,与之对应的数据库存储过程一般也只涉及到关系密切的几个表而已。但是当我们的B层业务需要对很多表进行操作时,用存储过程来保证事务性显得灵活性不够。那么怎样才能在B层使用事物呢?

            我上网查过很多资料,大部分都是用SqlTransaction这个类来在程序代码中保证事务性,但是SqlTransaction是与SQL Server数据库相关的类,如果将这个类用在了B层,那么就突破了三层架构的底线了,如果将来换数据库(比如从SQL Server换到Oracle),D层和B层都得重写,所以这样做的局限性很大。

          后来我在网上查到了一个轻量级的事物类TransactionScope,这个类是与具体数据库无关的类,用这个类来保证B层的事务性十分可行。

         下面说一下这个类的基本用法

          在TransactionScope中默认的事务级别是Serializable,即在事务过程中,完全性锁表。别的进程不能查询,修改,新增,删除。这样会导致效率大大降低,虽然数据完整性很高。通常我们不需要那么高的数据完整性。所以需要修改默认的事务级别:

    通过TransactionOptions类来改变事物的级别

    [csharp] view plaincopy
     
    1. TransactionOptions option = new TransactionOptions();  
    2. option.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;  

    然后用option作为TransactionScope的构造函数的参数就可以建立低级别的TransactionScope对象了
    [csharp] view plaincopy
     
    1. using(TransactionScope scope=new TransactionScope(TransactionScopeOption.Required,option))  
    2. {  
    3.       //此处为需要保证事务性的多个方法  
    4.         
    5.       if(方法全部执行成功)  
    6.       {  
    7.             scope.Complete();//提交事务  
    8.       }  
    9. }  
    
    
    注:方法是否执行成功可以通过方法的返回值来判断,因为B层调用D层的方法返回的一般都是bool值,所以只要所有的方法返回值都是true,那么就可以提交事务了,否则将不提交事务,using中的代码相当于没有被执行一样
  • 相关阅读:
    【嵌入式开发】写入开发板Linux系统-模型S3C6410
    大约cocos2d-X 3.x使用引擎版本自带的物理引擎Physics
    它们的定义PropertyPlaceHolder无法完成更换任务
    [Cocos2d-x]在Cocos2d-x 3.x如何通过版本号WebSocket连接server数据的传输
    Java 内存架构
    类似的微博推断客户关系sql声明
    Kienct与Arduino学习笔记(2) 深度图像与现实世界的深度图的坐标
    etl工具,kettle实现了周期
    Android中自定义checkbox样式
    ndroid网络(4):HttpClient必经之路----使用线程安全的单例模式HttpClient,及HttpClient和Application的融合
  • 原文地址:https://www.cnblogs.com/zcm123/p/4377224.html
Copyright © 2020-2023  润新知