TransactionScope的使用

简介

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

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

1. 命名空间

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

using System.Transactions;

2.创建事务范围

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

using (TransactionScope scope = new TransactionScope())
{
    // 在这里执行事务性操作
}

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

这种默认行为可以通过在 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();
                }

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

正常抛出异常

在这里插入图片描述

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

在这里插入图片描述

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


        }

抛出异常

在这里插入图片描述

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

在这里插入图片描述

显式事务对象

将 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有诗亦有远方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值