• TransactionScope事务类的使用


    如果在C#中使用TransactionScope类(分布式事务),则须注意如下事项:
    1、在项目中引用using System.Transactions命名空间(先要在添加net组件的引用);

    2、具体示例如下:
      

            /// <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;
            }


     3、对MSDTC组件设置:
     步骤:
      在控制面板--->管理工具--->服务 中,开启Distributed Transaction Coordinator 服务。
     a.控制面板->管理工具->组件服务->计算机->我的电脑->右键->属性
     b.选择MSDTC页, 确认"使用本地协调器"
     c.点击下方"安全配置"按钮
     d.勾选: "允许网络DTC访问","允许远程客户端","允许入站","允许出站","不要求进行身份验证".
     e.对于数据库服务器端, 可选择"要求对呼叫方验证"
     f.勾选:"启用事务Internet协议(TIP)事务"。
     g.在双方防火墙中增加MSDTC.exe例外
       可用命令行: netsh firewall set allowedprogram %windir%system32msdtc.exe MSDTC enable

    4、重启IIS服务器

    一、在TransactionScope中,如果不是必须要避免它启用DTC分布式事务,因为性能低下;而对于TransactionScope来说它是以连接对象Connection做为识别单位的,也就是说即便是相同连接字符串ConnectionString的两个连接对象Connection在TransactionScope也是会启用DTC分布式事务的,避免的方法就是在一个TransactionScope中使用一个唯一的连接对象Connection。


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

                    TransactionOptions option = new TransactionOptions();
                    option.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
                    using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, option))


          所有的事务级别如下:

    成员名称 说明 
     Chaos                         无法改写隔离级别更高的事务中的挂起的更改。  
     ReadCommitted       不可以在事务期间读取可变数据,但是可以修改它。  
     ReadUncommitted    可以在事务期间读取和修改可变数据。  
     RepeatableRead       可以在事务期间读取可变数据,但是不可以修改。可以在事务期间添加新数据。  
     Serializable                可以在事务期间读取可变数据,但是不可以修改,也不可以添加任何新数据。  
     Snapshot                   可以读取可变数据。在事务修改数据之前,它验证在它最初读取数据之后另一个事务是否更改过这些数据。如果数据已被更新,则会引发错误。这样使事务可获取先前提交的数据值。 
    在尝试提升以此隔离级别创建的事务时,将引发一个 InvalidOperationException,并产生错误信息“Transactions with IsolationLevel Snapshot cannot be promoted”(无法提升具有 IsolationLevel 快照的事务)。
     
     Unspecified                正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。如果设置了此值,则会引发异常。  
     
     

    一. 事务

    在项目中使用事务是很常见的,这里介绍Entity Framework使用TransactionScope

        添加引用 System.Transactions.dll

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        var entities = new EntityDBContext();
     
        USER_INFO userInfo = new USER_INFO()
        {
            USERNAME = "mike2",
            USER_PWD = "22222",
            STATUS_CODE = 0,
            REMARK = "EF测试"
        };
        entities.Insert(userInfo);
     
        USER_ROLE_INFO userRoleInfo = new USER_ROLE_INFO()
        {
            ROLE_NAME = "管理员",
            REMARK = ""
        };
        entities.Insert(userRoleInfo);
     
        transactionScope.Complete();
    }

    这样一个简单的事务就写好了,表USER_INFO和USER_ROLE_INFO要么都插入成功,要么都插入失败

    二. 批量操作

     1. 如果插入很多条数据,常规做法就是一条一条插入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        DateTime dtStart = DateTime.Now;
        var entities = new EntityDBContext();
     
        for (int i = 0; i < 2000; i++)
        {
            USER_INFO userInfo = new USER_INFO()
            {
                USERNAME = "mike_i_" + i,
                USER_PWD = "22222",
                STATUS_CODE = 0,
                REMARK = "EF测试"
            };
            entities.Insert(userInfo);
        }
        transactionScope.Complete();
    }

    这里插入2000条,耗时24秒

    2. 利用EntityFramework扩展插件进行批量插入 

    安装方法: PM> Install-Package Z.EntityFramework.Extensions -Version 3.14.0

    使用介绍: http://entityframework-extensions.net/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var entities = new EntityDBContext();
    List<USER_INFO> userInfolist = new List<USER_INFO>();
    for (int i = 0; i < 2000; i++)
    {
        userInfolist.Add(new USER_INFO()
        {
            USERNAME = "mike_i_" + i,
            USER_PWD = "22222",
            STATUS_CODE = 0,
            REMARK = "EF批量操作"
        });
    }
    //批量插入
    entities.BulkInsert(userInfolist);

    同样是插入2000条,耗时834毫秒

    3. 批量删除

    1
    2
    3
    4
    5
    var entities = new EntityDBContext();
    //方法一
    entities.BulkDelete(entities.USER_INFO.Where(q => q.USERID == 21608));
    //方法二
    entities.USER_INFO.Where(q => q.USERID == 21612).DeleteFromQuery();

    4. 批量更新

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var entities = new EntityDBContext();
    var userUpdateList = entities.USER_INFO.Where(q => q.USERID == 21613).ToList();
    //这里修改下需要被更新的字段
    userUpdateList.ForEach(q =>
    {
        q.USERNAME = "BulkUpdate更新名称";
        q.USER_PWD = "BulkUpdate更新密码";
    });
    //批量更新这两个字段(方法一)
    entities.BulkUpdate(userUpdateList);
    //批量将USERNAME修改为 "21614"(方法二)
    entities.USER_INFO.Where(q => q.USERID == 21614).UpdateFromQuery(q => new USER_INFO() { USERNAME = "21614" });

    三. 事务和批量操作结合使用

    也是通过使用TransactionScope来使用事务,用法和上面类似

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        var entities = new EntityDBContext();
        DateTime dtStart = DateTime.Now;
        List<USER_INFO> userInfolist = new List<USER_INFO>();
        for (int i = 0; i < 2000; i++)
        {
            userInfolist.Add(new USER_INFO()
            {
                USERNAME = "mike_i_" + i,
                USER_PWD = "22222",
                STATUS_CODE = 0,
                REMARK = "EF批量操作"
            });
        }
        entities.BulkInsert(userInfolist);
     
        entities.USER_INFO.Where(q => q.USERID == 21610).UpdateFromQuery(q => new USER_INFO() { USERNAME = "test" });
     
        transactionScope.Complete();
    }
  • 相关阅读:
    一步一步学EF系列【4、升级篇 实体与数据库的映射】live writer真坑,第4次补发
    一步一步学EF系列3【升级篇 实体与数据库的映射】
    一步一步学EF系列2【最简单的一个实例】
    一步一步学EF系列1【Fluent API的方式来处理实体与数据表之间的映射关系】
    MVC5 Entity Framework学习之创建复杂的数据模型
    Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
    动手写一个Remoting接口测试工具(附源码下载)
    通信服务器群集——跨服务器通信Demo(源码)
    轻量级通信引擎StriveEngine —— C/S通信demo(2) —— 使用二进制协议 (附源码)
    PAT A1011 World Cup Betting(20)
  • 原文地址:https://www.cnblogs.com/Alex80/p/15205887.html
Copyright © 2020-2023  润新知