C#事务处理机制详解


1. 事务的基本概念

事务(Transaction)是数据库操作中的一个重要概念,它代表一组必须全部成功或全部失败的操作单元。事务具有ACID四大特性:

  • 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成
  • 一致性(Consistency):事务执行前后,数据库从一个一致状态变到另一个一致状态
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务
  • 持久性(Durability):一旦事务提交,其结果就是永久性的

在C#中,我们可以通过多种方式实现事务处理,包括ADO.NET事务、Entity Framework事务以及System.Transactions命名空间提供的分布式事务支持。

2. ADO.NET事务处理

2.1 基本事务处理

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    SqlTransaction transaction = connection.BeginTransaction();

    try
    {
        using (SqlCommand command = new SqlCommand("INSERT INTO Table1...", connection, transaction))
        {
            command.ExecuteNonQuery();
        }

        using (SqlCommand command = new SqlCommand("UPDATE Table2...", connection, transaction))
        {
            command.ExecuteNonQuery();
        }

        transaction.Commit();
        Console.WriteLine("事务提交成功");
    }
    catch (Exception ex)
    {
        transaction.Rollback();
        Console.WriteLine($"事务回滚,原因: {ex.Message}");
    }
}

2.2 保存点(SavePoint)

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    SqlTransaction transaction = connection.BeginTransaction();

    try
    {
        // 第一个操作
        using (SqlCommand command = new SqlCommand("INSERT INTO Table1...", connection, transaction))
        {
            command.ExecuteNonQuery();
        }

        // 创建保存点
        transaction.Save("SavePoint1");

        try
        {
            // 第二个操作
            using (SqlCommand command = new SqlCommand("UPDATE Table2...", connection, transaction))
            {
                command.ExecuteNonQuery();
            }
        }
        catch
        {
            // 回滚到保存点,而不是整个事务
            transaction.Rollback("SavePoint1");
            throw;
        }

        transaction.Commit();
    }
    catch (Exception ex)
    {
        transaction.Rollback();
        Console.WriteLine($"事务回滚,原因: {ex.Message}");
    }
}

3. Entity Framework事务处理

3.1 DbContext自带事务

using (var context = new MyDbContext())
{
    try
    {
        context.Products.Add(new Product { Name = "Product1" });
        context.Customers.Add(new Customer { Name = "Customer1" });

        // SaveChanges会自动开启并提交事务
        context.SaveChanges();
        Console.WriteLine("事务提交成功");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"操作失败: {ex.Message}");
    }
}

3.2 显式事务控制

using (var context = new MyDbContext())
{
    using (var transaction = context.Database.BeginTransaction())
    {
        try
        {
            context.Products.Add(new Product { Name = "Product1" });
            context.SaveChanges();

            context.Customers.Add(new Customer { Name = "Customer1" });
            context.SaveChanges();

            transaction.Commit();
            Console.WriteLine("事务提交成功");
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            Console.WriteLine($"事务回滚,原因: {ex.Message}");
        }
    }
}

4. System.Transactions分布式事务

当需要跨多个数据库或资源管理器进行事务操作时,可以使用System.Transactions。

using (TransactionScope scope = new TransactionScope())
{
    try
    {
        // 第一个数据库操作
        using (SqlConnection connection1 = new SqlConnection(connectionString1))
        {
            connection1.Open();
            SqlCommand command1 = new SqlCommand("INSERT INTO Table1...", connection1);
            command1.ExecuteNonQuery();
        }

        // 第二个数据库操作
        using (SqlConnection connection2 = new SqlConnection(connectionString2))
        {
            connection2.Open();
            SqlCommand command2 = new SqlCommand("UPDATE Table2...", connection2);
            command2.ExecuteNonQuery();
        }

        scope.Complete();
        Console.WriteLine("分布式事务提交成功");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"分布式事务失败: {ex.Message}");
    }
}

5. 事务隔离级别

C#支持不同的事务隔离级别,可以在创建事务时指定:

// ADO.NET中设置隔离级别
SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);

// Entity Framework中设置隔离级别
using (var transaction = context.Database.BeginTransaction(IsolationLevel.Serializable))
{
    // ...
}

// System.Transactions中设置隔离级别
var options = new TransactionOptions
{
    IsolationLevel = IsolationLevel.RepeatableRead,
    Timeout = TimeSpan.FromSeconds(30)
};
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options))
{
    // ...
}

常用隔离级别:

  • ReadUncommitted:最低隔离级别,允许读取未提交的数据
  • ReadCommitted:只能读取已提交的数据(默认级别)
  • RepeatableRead:确保在同一事务中多次读取相同数据结果一致
  • Serializable:最高隔离级别,完全隔离事务
  • Snapshot:使用行版本控制避免读取阻塞

6. 事务最佳实践

  1. 保持事务简短:长时间运行的事务会锁定资源,影响系统性能
  2. 合理设置隔离级别:根据业务需求选择最低合适的隔离级别
  3. 正确处理异常:确保在异常情况下事务能够正确回滚
  4. 避免分布式事务:分布式事务性能开销大,应尽可能避免
  5. 使用using语句:确保连接和事务对象能够正确释放
  6. 考虑重试机制:对于可能因并发冲突失败的操作,实现重试逻辑

7. 总结

C#提供了丰富的事务处理机制,从简单的ADO.NET事务到复杂的分布式事务支持。开发者应根据具体应用场景选择合适的事务处理方式,并遵循事务处理的最佳实践,以确保数据的一致性和系统的可靠性。


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注