首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【愚公系列】2023年09月 .NET/C#知识点-EF的事务和环境事务

【愚公系列】2023年09月 .NET/C#知识点-EF的事务和环境事务

作者头像
愚公搬代码
发布2025-05-31 16:17:41
发布2025-05-31 16:17:41
1980
举报
文章被收录于专栏:历史专栏历史专栏

前言

事务是指一系列的操作,要么全部执行成功,要么全部不执行,不允许出现部分执行成功部分执行失败的情况。事务的作用是保证数据一致性,确保多个操作的执行结果是原子性的,保证数据的完整性和正确性。

分布式事务是指在分布式系统中进行的跨多个节点或多个数据库的事务。在分布式环境中,由于数据分散在多个节点上,需要保证整个分布式事务的一致性,即所有节点要么全部执行成功,要么全部不执行。因此,分布式事务的意义在于保证数据的一致性、可靠性和完整性,防止数据的丢失和重复,实现分布式系统的高可用和高性能。

分布式事务的实现方式有很多种,包括两阶段提交协议、三阶段提交协议、补偿事务等。其中,两阶段提交协议是最经典的实现方式,它通过预提交、提交和回滚三个阶段来保证整个分布式事务的一致性,但也存在一些问题,比如性能和可扩展性较差等。因此,在实际的分布式系统中需要根据具体的场景和需求选择合适的分布式事务实现方式。

一、EF的事务和环境事务

1.EF的事务

在EF中,BeginTransaction是一种开启事务的方法,它允许我们在一个事务范围内执行多个操作,并确保这些操作要么全部执行成功,要么全部回滚。

使用BeginTransaction方法的步骤如下:

  1. 创建DbContext对象,这是EF中的数据上下文;
  2. 实例化一个DbContextTransaction对象,它代表一个事务;
  3. 调用DbContext的Database.BeginTransaction()方法,返回一个DbContextTransaction对象,表示开始一个事务;
  4. 在事务范围内执行需要支持事务的操作;
  5. 调用DbContextTransaction的Commit()方法来提交事务,或者调用Rollback()方法来回滚事务。

下面是一个使用BeginTransaction方法开启事务的例子:

代码语言:javascript
复制
using (var db = new MyDbContext())
{
    using (var transaction = db.Database.BeginTransaction())
    {
        try
        {
            //在事务范围内执行需要支持事务的操作,比如:
            db.Customers.Add(new Customer { Name = "Alice" });
            db.Orders.Add(new Order { CustomerId = 1, TotalPrice = 100 });
            db.SaveChanges();

            //提交事务
            transaction.Commit();
        }
        catch (Exception ex)
        {
            //发生异常时回滚事务
            transaction.Rollback();
            Console.WriteLine("Error: " + ex.Message);
        }
    }
}

在这个例子中,我们先创建了一个MyDbContext对象,然后使用BeginTransaction方法开始一个事务,最后调用Commit方法提交事务,或者在发生异常时调用Rollback方法回滚事务。

需要注意的是,当使用BeginTransaction方法开启事务时,要确保在操作完成后要调用Commit方法来提交事务或者Rollback方法来回滚事务,否则将会造成数据不一致的问题。

2.环境事务

2.1 TransactionScope

System.Transactions是C#中用于实现环境事务的一个命名空间。环境事务(也称为分布式事务)是指涉及多个数据源(如多个数据库、消息队列等)的事务,它需要在多个数据源之间保持一致性。System.Transactions提供了一种简单、可靠、可扩展的方式来处理这种类型的事务。

System.Transactions是一种基于.NET Framwork的事务处理机制,它提供了TransactionScope类来管理事务,并兼容多种数据源,如ADO.NET、Message Queue等。

使用System.Transactions的步骤如下:

  1. 创建TransactionScope对象,它表示环境事务;
  2. 在TransactionScope对象的范围内执行需要支持环境事务的操作;
  3. 调用TransactionScope对象的Complete()方法来提交事务,或者让代码退出TransactionScope代码块并没有调用Complete方法,此时事务将会自动回滚。

下面是一个使用TransactionScope对象管理事务的例子:

代码语言:javascript
复制
using (var scope = new TransactionScope(
    TransactionScopeOption.Required,
    new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
    using var connection = new SqlConnection(connectionString);
    connection.Open();

    try
    {
        // Run raw ADO.NET command in the transaction
        var command = connection.CreateCommand();
        command.CommandText = "DELETE FROM dbo.Blogs";
        command.ExecuteNonQuery();

        // Run an EF Core command in the transaction
        var options = new DbContextOptionsBuilder<BloggingContext>()
            .UseSqlServer(connection)
            .Options;

        using (var context = new BloggingContext(options))
        {
            context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
            context.SaveChanges();
        }

        // Commit transaction if all commands succeed, transaction will auto-rollback
        // when disposed if either commands fails
        scope.Complete();
    }
    catch (Exception)
    {
        // TODO: Handle failure
    }
}

在这个例子中,我们使用TransactionScope对象来管理环境事务,然后在TransactionScope代码块中执行了两个SqlConnection对象所代表的数据源的操作,最后调用Complete方法来提交事务。

需要注意的是,当使用TransactionScope对象管理事务时,一定要确保在事务范围内执行的操作都支持事务,否则可能会导致数据不一致的问题。此外,使用TransactionScope对象管理事务时,也需要确保数据源支持分布式事务,否则将会抛出NotSupportedException异常。

2.2 CommittableTransaction

CommittableTransaction是.net framework提供的一种事务机制,它可以用于控制多个资源(例如数据库和文件系统)在事务性操作期间的一致性。

CommittableTransaction是通过System.Transactions命名空间提供的,它提供了以下几个重要的方法:

  1. Begin:创建一个新的CommittableTransaction对象。
  2. Commit:提交事务,使之生效。
  3. Rollback:回滚事务,取消之前的操作。
  4. EnlistResource:将一个资源加入到事务中。

使用CommittableTransaction时,通常需要遵循以下步骤:

  1. 创建CommittableTransaction对象。
  2. 将需要参与事务的资源加入到事务中。
  3. 执行操作(例如数据库的更新或文件系统的写入)。
  4. 如果操作成功,调用Commit方法提交事务。
  5. 如果操作失败,调用Rollback方法回滚事务。

以下是一个使用CommittableTransaction的示例代码:

代码语言:javascript
复制
using (var transaction = new CommittableTransaction(
    new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
    var connection = new SqlConnection(connectionString);

    try
    {
        var options = new DbContextOptionsBuilder<BloggingContext>()
            .UseSqlServer(connection)
            .Options;

        using (var context = new BloggingContext(options))
        {
            context.Database.OpenConnection();
            context.Database.EnlistTransaction(transaction);

            // Run raw ADO.NET command in the transaction
            var command = connection.CreateCommand();
            command.CommandText = "DELETE FROM dbo.Blogs";
            command.ExecuteNonQuery();

            // Run an EF Core command in the transaction
            context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
            context.SaveChanges();
            context.Database.CloseConnection();
        }

        // Commit transaction if all commands succeed, transaction will auto-rollback
        // when disposed if either commands fails
        transaction.Commit();
    }
    catch (Exception)
    {
        // TODO: Handle failure
    }
}

在上面的示例中,我们使用CommittableTransaction控制了一个数据库更新操作的事务,如果操作成功,我们会提交事务,否则回滚事务。

2.3 CommittableTransaction 和TransactionScope区别

CommittableTransaction和TransactionScope都是.NET Framework中提供的用于管理事务的类,它们的最主要区别在于使用的方式和事务管理的粒度。

CommittableTransaction是一种显示地在代码中创建和管理的事务对象,它要求开发者手动指定需要管理的资源,以及何时提交或回滚事务。通常情况下,CommittableTransaction被用于在代码中执行自定义的事务管理逻辑时。

而TransactionScope则是一种更高层次的事务管理类,它可以自动地管理多个事务性资源的事务性操作。使用TransactionScope时,开发者只需要将需要在同一个事务中执行的代码块放在一个TransactionScope对象中即可,事务的管理和提交或回滚都由TransactionScope对象实例自动完成。

具体而言,CommittableTransaction需要显式地在代码中进行事务管理,需要手动指定事务需要管理的资源和何时提交或回滚事务,而TransactionScope则通过自动管理资源和事务性操作,为开发者提供了更加高层次的事务管理方式。

需要注意的是,TransactionScope内部也是使用CommittableTransaction来实现事务管理的,只不过是对其进行了封装,使用起来更加方便和简单。

2.4 System.Transactions 的限制

System.Transactions 有以下限制:

  1. 只能在支持分布式事务的数据库中使用。不支持分布式事务的数据库无法通过 System.Transactions 进行事务处理。
  2. 在分布式事务中,由于需要协调多个参与者的操作,因此可能会出现性能问题。
  3. System.Transactions 只能处理数据库事务和消息队列事务,无法用于其他类型的事务处理,如文件系统事务等。
  4. 在分布式事务中,如果其中一个参与者发生故障,那么整个事务可能会失败或需要回滚。这可能会导致数据丢失或应用程序中的异常。
  5. 在某些情况下,由于 System.Transactions 的限制,可能需要手动编写分布式事务处理代码。这可能会导致更多的工作量和复杂性。
  6. 自 .NET Core 2.1 起,System.Transactions 实现不包括对分布式事务的支持,因此不能使用 TransactionScope 或 CommittableTransaction 来跨多个资源管理器协调事务。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、EF的事务和环境事务
    • 1.EF的事务
    • 2.环境事务
      • 2.1 TransactionScope
      • 2.2 CommittableTransaction
      • 2.3 CommittableTransaction 和TransactionScope区别
      • 2.4 System.Transactions 的限制
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档