一、事务管理的基本概念

在软件开发中,事务(Transaction)是指一系列操作要么全部成功,要么全部失败。比如你在网上购物,支付成功后库存减少,这两个操作必须同时成功或同时回滚,否则就会出现数据不一致的问题。

在单数据库环境下,事务管理相对简单,比如使用SqlTransaction或者DbContextSaveChanges就能搞定。但在分布式系统中,多个服务可能使用不同的数据库,甚至不同的存储技术(如SQL Server + Redis),这时候就需要分布式事务来确保数据一致性。

二、Entity Framework Core 中的事务

Entity Framework Core(EF Core)是.NET Core中常用的ORM框架,它提供了简单的事务管理机制。我们先来看一个基本的事务示例:

// 示例技术栈:.NET Core + EF Core + SQL Server
using (var transaction = context.Database.BeginTransaction())
{
    try
    {
        // 操作1:新增用户
        var user = new User { Name = "张三" };
        context.Users.Add(user);
        await context.SaveChangesAsync();

        // 操作2:新增订单
        var order = new Order { UserId = user.Id, Amount = 100 };
        context.Orders.Add(order);
        await context.SaveChangesAsync();

        // 提交事务
        await transaction.CommitAsync();
    }
    catch (Exception)
    {
        // 回滚事务
        await transaction.RollbackAsync();
        throw;
    }
}

这个例子演示了如何在单个数据库中使用事务。但如果你的系统涉及多个数据库,比如一个操作要同时写入SQL Server和MySQL,那该怎么办?

三、分布式事务的挑战

分布式事务的核心问题是如何保证多个独立的数据存储系统的事务一致性。传统的解决方案是两阶段提交(2PC),但它的性能较差,且对系统要求较高。

在.NET生态中,可以使用Microsoft Distributed Transaction Coordinator (MSDTC),但它依赖Windows环境,在跨平台场景下不太适用。

更现代的方案是采用最终一致性(Eventual Consistency),结合消息队列(如RabbitMQ、Kafka)Saga模式来实现。

四、基于Saga模式的分布式事务

Saga模式的核心思想是将一个大事务拆分成多个小事务,每个小事务有对应的补偿操作。如果某个步骤失败,就执行之前的补偿操作来回滚。

下面是一个基于EF Core和RabbitMQ的Saga示例:

// 示例技术栈:.NET Core + EF Core + RabbitMQ
public async Task HandleOrderCreation(OrderCreatedEvent @event)
{
    using (var transaction = dbContext.Database.BeginTransaction())
    {
        try
        {
            // 步骤1:扣减库存
            var product = await dbContext.Products.FindAsync(@event.ProductId);
            product.Stock -= @event.Quantity;
            await dbContext.SaveChangesAsync();

            // 步骤2:发布“库存已扣减”事件
            await rabbitMq.PublishAsync(new InventoryDeductedEvent
            {
                OrderId = @event.OrderId,
                ProductId = @event.ProductId
            });

            // 提交事务
            await transaction.CommitAsync();
        }
        catch (Exception)
        {
            // 失败时发布“库存回滚”事件
            await rabbitMq.PublishAsync(new InventoryRollbackEvent
            {
                ProductId = @event.ProductId,
                Quantity = @event.Quantity
            });
            await transaction.RollbackAsync();
        }
    }
}

这个例子展示了Saga的编排模式,即每个步骤完成后,发布事件触发下一步操作。如果某一步失败,就触发补偿逻辑。

五、其他分布式事务方案

除了Saga,还可以使用TCC(Try-Confirm-Cancel)模式,或者结合Polly做重试机制。

// 示例技术栈:.NET Core + Polly
var retryPolicy = Policy
    .Handle<Exception>()
    .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt));

await retryPolicy.ExecuteAsync(async () =>
{
    using (var transaction = dbContext.Database.BeginTransaction())
    {
        // 业务逻辑...
        await transaction.CommitAsync();
    }
});

六、应用场景与优缺点

适用场景

  1. 电商系统:订单、库存、支付等多个服务需要事务一致性。
  2. 金融系统:转账操作涉及多个账户,必须保证原子性。
  3. 微服务架构:多个服务使用不同数据库,但业务上需要强一致性。

优缺点

方案 优点 缺点
2PC 强一致性 性能差,依赖协调者
Saga 高性能,适合微服务 实现复杂,需要补偿逻辑
TCC 灵活性高 代码侵入性强

注意事项

  1. 避免长事务:分布式事务尽量短,减少锁竞争。
  2. 幂等性设计:补偿操作必须支持重复执行。
  3. 监控与日志:分布式事务的调试较复杂,需要完善的日志。

七、总结

分布式事务是微服务架构中的难点,EF Core提供了基础的事务支持,但在跨服务场景下需要结合Saga、TCC等模式。选择合适的方案取决于业务需求,强一致性高可用性往往需要权衡。