SpringBoot + Seata + Nacos:分布式事务落地实战,订单-库存一致性全解析

SpringBoot + Seata + Nacos:分布式事务落地实战,订单-库存一致性全解析

你是否曾在面对复杂的微服务架构时,为数据一致性问题而头疼不已?特别是在订单系统和库存系统分离的情况下,如何保证订单创建和库存扣减的原子性?今天我们就来深入探讨如何使用SpringBoot + Seata + Nacos这套黄金组合,完美解决分布式事务的一致性问题,让你的系统在高并发场景下依然保持数据的绝对一致!

一、分布式事务的痛点

在传统的单体应用中,我们可以通过数据库事务轻松保证数据的一致性。但在微服务架构下,业务被拆分成多个独立的服务,每个服务都有自己的数据库。以电商场景为例:

  1. 用户下单(订单服务)
  2. 扣减库存(库存服务)

这两个操作必须同时成功或同时失败,否则就会出现数据不一致的情况。

二、Seata是什么?

Seata是阿里巴巴开源的一款分布式事务解决方案,提供了高性能和简单易用的分布式事务服务。它支持AT、TCC、Saga和XA事务模式,其中AT模式对业务代码侵入最小。

三、项目架构设计

我们的示例项目包含以下模块:

  • order-service(订单服务)
  • inventory-service(库存服务)
  • common(公共模块)

四、核心技术实现

4.1 项目依赖配置

首先在pom.xml中引入必要的依赖:

<!-- Seata -->
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
</dependency>

<!-- Spring Cloud Alibaba Nacos Discovery -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

4.2 Seata配置

在application.yml中配置Seata:

spring:
  seata:
    enabled: true
    application-id: ${spring.application.name}
    tx-service-group: order_tx_group
    enable-auto-data-source-proxy: false
    service:
      vgroup-mapping:
        order_tx_group: default
      grouplist:
        default: 127.0.0.1:8091

4.3 数据源代理配置

为了使Seata能够拦截并管理事务,我们需要配置数据源代理:

@Configuration
public class SeataConfig {
    
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }
    
    @Primary
    @Bean("dataSourceProxy")
    public DataSourceProxy dataSourceProxy(DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }
}

4.4 全局事务注解

在需要开启分布式事务的方法上添加@GlobalTransactional注解:

@Service
public class OrderServiceImpl implements OrderService {
    
    @Override
    @GlobalTransactional // 开启全局事务
    public Long createOrder(Long userId, Long productId, Integer count, BigDecimal money) {
        // 业务逻辑
    }
}

4.5 完整业务流程

让我们来看一个完整的购买流程实现:

@RestController
@RequestMapping("/business")
@Slf4j
public class BusinessController {
    
    @PostMapping("/purchase")
    @GlobalTransactional // 开启全局事务
    public Result<String> purchase(@RequestParam("userId") Long userId,
                                 @RequestParam("productId") Long productId,
                                 @RequestParam("count") Integer count,
                                 @RequestParam("money") BigDecimal money) {
        try {
            log.info("开始购买流程,用户ID:{},产品ID:{},数量:{},金额:{}", userId, productId, count, money);
            
            // 1. 创建订单
            Long orderId = orderService.createOrder(userId, productId, count, money);
            log.info("订单创建成功,订单ID:{}", orderId);
            
            // 2. 扣减库存(调用库存服务)
            String inventoryUrl = "http://inventory-service/product/decreaseStock?productId=" + productId + "&count=" + count;
            Result<Boolean> inventoryResult = restTemplate.postForObject(inventoryUrl, null, Result.class);
            
            if (!inventoryResult.getCode().equals(200)) {
                throw new RuntimeException("库存扣减失败:" + inventoryResult.getMessage());
            }
            
            log.info("库存扣减成功");
            
            // 3. 更新订单状态为已完成
            orderService.updateOrderStatus(orderId, 1);
            log.info("订单状态更新成功");
            
            return Result.success("购买成功");
        } catch (Exception e) {
            log.error("购买失败", e);
            throw e; // Seata会捕获这个异常并回滚事务
        }
    }
}

五、异常处理与事务回滚

当业务流程中发生异常时,Seata会自动触发事务回滚机制,确保数据一致性:

@PostMapping("/purchaseWithError")
@GlobalTransactional // 开启全局事务
public Result<String> purchaseWithError(@RequestParam("userId") Long userId,
                                      @RequestParam("productId") Long productId,
                                      @RequestParam("count") Integer count,
                                      @RequestParam("money") BigDecimal money) {
    try {
        // 业务逻辑...
        
        // 模拟业务异常
        throw new RuntimeException("模拟业务异常,触发事务回滚");
        
    } catch (Exception e) {
        log.error("购买失败", e);
        throw e; // Seata会捕获这个异常并回滚事务
    }
}

六、Nacos服务注册与发现

通过Nacos,我们可以实现服务的自动注册与发现,让服务间的调用更加便捷:

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

七、最佳实践建议

  1. 合理设置超时时间:根据业务特点设置合适的事务超时时间
  2. 异常处理:确保所有异常都能被正确捕获并传播给Seata
  3. 监控告警:建立完善的分布式事务监控体系
  4. 性能优化:避免长时间持有数据库连接

八、总结

通过SpringBoot + Seata + Nacos的组合,我们能够轻松实现分布式事务的一致性保障。这套方案不仅降低了开发复杂度,还提供了良好的性能表现和扩展能力。

在实际项目中,我们只需要在关键业务方法上添加@GlobalTransactional注解,就能享受到分布式事务带来的数据安全保障。同时配合Nacos的服务治理能力,构建出稳定可靠的微服务架构。

希望这篇文章能帮助你在分布式事务的道路上走得更远,让你的系统在面对复杂业务场景时依然稳如泰山!


关注我,获取更多后端技术干货!


标题:SpringBoot + Seata + Nacos:分布式事务落地实战,订单-库存一致性全解析
作者:jiangyi
地址:http://jiangyi.space/articles/2025/12/21/1766304276708.html

    0 评论
avatar