• TransactionScope的使用


    简介

    TransactionScope 是 .NET Framework 和 .NET Core 中的一个类,用于简化事务管理。它提供了一种简单的方式来创建分布式事务和本地事务,以确保一系列操作要么全部成功提交,要么全部回滚,以保持数据的一致性

    需要注意的是,TransactionScope 的使用需要系统支持 MSDTC,因此不是所有的环境都适合使用它。在某些情况下,特别是在高性能的场景中,可能需要权衡使用 TransactionScope 的方便性和性能开销。

    1. 命名空间

    在代码中使用 TransactionScope 时,需要导入以下命名空间:

    using System.Transactions;

    2.创建事务范围

    要使用 TransactionScope,您可以通过创建一个新的 TransactionScope 对象来定义一个事务范围。这个事务范围将包裹一系列数据库或其他资源操作。

    using (TransactionScope scope = new TransactionScope())
    {
        // 在这里执行事务性操作
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.嵌套事务

    您可以在代码中嵌套多个 TransactionScope 对象,形成多层嵌套的事务。在这种情况下,只有最外层的事务范围会影响整个事务。如果内部的事务范围失败,它们会自动回滚,而最外层的事务范围可以选择提交或回滚整个事务

    在默认情况下,TransactionScope 中的嵌套事务,如果任何一个子事务发生错误并引发异常,整个事务将会被回滚。这是因为 TransactionScope 使用分布式事务协调器(Distributed Transaction Coordinator,DTC)来进行事务的管理,DTC 通常会对整个事务进行协调和控制。

            public async Task Transactions(int id)
            {
                try
                {
                    using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope())
                    {
                        Student item = _studentService.GetById(id).Result;
                        item.Name = new Random().Next(1, 100).ToString();
                        using (System.Transactions.TransactionScope scope1 = new System.Transactions.TransactionScope())
                        {
                            _studentService.Upate(item);
                            //throw new Exception();当抛出异常时,事务回滚不会更新数据。
                            scope1.Complete(); //嵌套事务也需要进行提交
                        }
                        item.Address = new Random().Next(100, 200).ToString();
                        _studentService.Upate(item);
                        //throw new Exception();//当我们注释掉内部嵌套的事务,在这里抛出异常,那么内部嵌套事务更改的数据也会回滚。
                        scope.Complete();
                    }
                }
                catch (ThreadAbortException ex)
                {
                    throw ex;
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    这种默认行为可以通过在 TransactionScope 构造函数中使用 TransactionScopeOption.Suppress 选项来更改,这将允许子事务独立于外部事务而不影响整体的事务结果。但在实际应用中,需要小心使用这种方式,确保不会破坏应用程序的一致性和可靠性。

    这里外部事务抛出异常,但是内部事务正常提交,数据更改成功。

    using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope())
                    {
                        Student item = _studentService.GetById(id).Result;
                        item.Name = new Random().Next(1, 100).ToString();
                        using (System.Transactions.TransactionScope scope1 = new System.Transactions.TransactionScope(TransactionScopeOption.Suppress,
                                                            new TransactionOptions
                                                            {
                                                                IsolationLevel = IsolationLevel.ReadCommitted,
                                                                Timeout = TimeSpan.FromSeconds(30)
                                                            }))
                        {
                            _studentService.Upate(item);
                            //throw new Exception();
                            scope1.Complete();
                        }
                        item.Address = new Random().Next(100, 200).ToString();
                        _studentService.Upate(item);
                        throw new Exception();
                        scope.Complete();
                    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    4.事务提交和回滚

    在 TransactionScope 中,如果代码成功执行,您可以调用 Complete() 方法来提交事务,确保所有操作都成功。如果在 TransactionScope 中发生异常或其他问题,事务将自动回滚,所有操作都将撤销。

    5.支持分布式事务

    TransactionScope 支持分布式事务,这意味着您可以在不同的数据库或资源上执行操作,并将它们包装在一个分布式事务中,以确保一致性。

    6.配置选项

    TransactionScope 允许您配置事务的选项,如超时时间、隔离级别等,以满足特定的业务需求。

    7.资源管理器

    TransactionScope 使用资源管理器来管理事务,这包括数据库、消息队列、文件系统等。每个资源管理器需要提供一个事务参与者,以便 TransactionScope 能够协调它们的事务。

    8.分布式事务协调器

    在分布式事务中,TransactionScope 使用分布式事务协调器(DTC)来协调事务。DTC 协调器确保所有事务参与者在提交或回滚时协调一致性。

    应用

    1.未设置分布式事务

    现有数据
    在这里插入图片描述
    这里没有设置事务,且通过NetCore+EF实现的增删改查功能

      [HttpGet]
            [Route("Transaction")]
            public async Task Transaction(int id)
            {
                try
                {
                    //using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope())
                    //{
                    //增加Student
                        _studentService.Add(new Student { Name = "DX", Address = "上城1", Sex = "男", Phone = "123456" });
    					//获取指定Id的Student
                        Student item = _studentService.GetById(id).Result;
                        //更新数据
                        _studentService.Upate(item);
                        //删除数据
                        _studentService.Delete(item);
                        //抛出异常
                        throw new Exception();
                        //scope.Complete();
                    //}
                }
                catch (ThreadAbortException ex)
                {
                   throw ex;
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    正常抛出异常

    在这里插入图片描述

    在不设置分布式事务的情况下,数据在抛出异常情况时,并未回滚操作,而是全部执行完成

    在这里插入图片描述

    2.设置分布式事务

       [HttpGet]
            [Route("Transaction")]
            public async Task Transaction(int id)
            {
                try
                {
                    using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope())
                    {
                        _studentService.Add(new Student { Name = "DX", Address = "上城1", Sex = "男", Phone = "123456" });
    
                        Student item = _studentService.GetById(id).Result;
                        _studentService.Upate(item);
                        _studentService.Delete(item);
                        throw new Exception();
                        scope.Complete();
                    }
                }
                catch (ThreadAbortException ex)
                {
                   throw ex;
                }
    
    
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    抛出异常

    在这里插入图片描述

    数据没有改变,说明因为抛出了异常所以进行了操作的回滚

    在这里插入图片描述

    显式事务对象

    将 TransactionScope 替换为显式事务管理,通常涉及以下步骤:

    1. 使用显式事务对象: 创建一个事务对象,通常是数据库提供的 DbTransaction 类的实例。这可能涉及到对具体数据库访问技术的了解,因为每个数据库访问技术(如 ADO.NET、Entity Framework 等)都有不同的事务管理方式。
    2. 开始事务: 在执行事务性操作之前,显式地开始事务。这通常涉及到调用事务对象的 BeginTransaction 方法。
    3. 执行事务性操作: 执行数据库操作时,确保将当前事务对象传递给相应的命令或操作。这可以通过将事务对象关联到 DbCommand.Transaction 属性,或者在使用 Entity Framework 时将事务对象传递给 DbContext.Database.BeginTransaction 方法。
    4. 提交或回滚事务: 根据操作的成功与否,决定是否提交或回滚事务。通常,成功时调用事务对象的 Commit 方法,失败时调用 Rollback 方法。
    using System;
    using System.Data.SqlClient;
    
    class Program
    {
        static void Main()
        {
            string connectionString = "your_connection_string";
    
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                connection.Open();
    
                // 显式开始事务
                SqlTransaction transaction = connection.BeginTransaction();
    
                try
                {
                    // 执行数据库操作
                    using (SqlCommand command = connection.CreateCommand())
                    {
                        command.Transaction = transaction;
                        command.CommandText = "UPDATE YourTable SET YourColumn = 'NewValue' WHERE YourCondition";
                        command.ExecuteNonQuery();
                    }
    
                    // 如果一切正常,显式提交事务
                    transaction.Commit();
                    Console.WriteLine("Transaction committed successfully.");
                }
                catch (Exception ex)
                {
                    // 发生异常时显式回滚事务
                    transaction.Rollback();
                    Console.WriteLine($"Transaction rolled back due to an exception: {ex.Message}");
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
  • 相关阅读:
    Github 2FA绑定中国+86手机号码实现两步验证
    Golang入门教程
    Windows 10 系统下解决 “Could not build wheels for pillow“
    【用户画像】在ClickHouse中将宽表转换为bitmap表(源码实现)、用户分群架构设计、SpringBoot概述及使用
    基于JavaSwing开发进销存管理系统的设计与实现 课程设计 大作业 毕业设计
    MarkDown简明语法手册
    【Axure高保真原型】输入宽高控制图片尺寸
    图解Base64
    Java项目之“拼图小游戏”
    二进制部署1.23.4版本k8s集群-2-安装DNS服务
  • 原文地址:https://blog.csdn.net/wsnbbdbbdbbdbb/article/details/133982638