TransactionScope 是 .NET Framework 和 .NET Core 中的一个类,用于简化事务管理。它提供了一种简单的方式来创建分布式事务和本地事务,以确保一系列操作要么全部成功提交,要么全部回滚,以保持数据的一致性
需要注意的是,TransactionScope 的使用需要系统支持 MSDTC,因此不是所有的环境都适合使用它。在某些情况下,特别是在高性能的场景中,可能需要权衡使用 TransactionScope 的方便性和性能开销。
在代码中使用 TransactionScope 时,需要导入以下命名空间:
using System.Transactions;
要使用 TransactionScope,您可以通过创建一个新的 TransactionScope 对象来定义一个事务范围。这个事务范围将包裹一系列数据库或其他资源操作。
using (TransactionScope scope = new TransactionScope())
{
// 在这里执行事务性操作
}
您可以在代码中嵌套多个 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();
}
在 TransactionScope 中,如果代码成功执行,您可以调用 Complete() 方法来提交事务,确保所有操作都成功。如果在 TransactionScope 中发生异常或其他问题,事务将自动回滚,所有操作都将撤销。
TransactionScope 支持分布式事务,这意味着您可以在不同的数据库或资源上执行操作,并将它们包装在一个分布式事务中,以确保一致性。
TransactionScope 允许您配置事务的选项,如超时时间、隔离级别等,以满足特定的业务需求。
TransactionScope 使用资源管理器来管理事务,这包括数据库、消息队列、文件系统等。每个资源管理器需要提供一个事务参与者,以便 TransactionScope 能够协调它们的事务。
在分布式事务中,TransactionScope 使用分布式事务协调器(DTC)来协调事务。DTC 协调器确保所有事务参与者在提交或回滚时协调一致性。
现有数据
这里没有设置事务,且通过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;
}
}
正常抛出异常

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

[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 替换为显式事务管理,通常涉及以下步骤:
- 使用显式事务对象: 创建一个事务对象,通常是数据库提供的 DbTransaction 类的实例。这可能涉及到对具体数据库访问技术的了解,因为每个数据库访问技术(如 ADO.NET、Entity Framework 等)都有不同的事务管理方式。
- 开始事务: 在执行事务性操作之前,显式地开始事务。这通常涉及到调用事务对象的 BeginTransaction 方法。
- 执行事务性操作: 执行数据库操作时,确保将当前事务对象传递给相应的命令或操作。这可以通过将事务对象关联到 DbCommand.Transaction 属性,或者在使用 Entity Framework 时将事务对象传递给 DbContext.Database.BeginTransaction 方法。
- 提交或回滚事务: 根据操作的成功与否,决定是否提交或回滚事务。通常,成功时调用事务对象的 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}");
}
}
}
}