每日Java面试场景题知识点之-Spring Boot微服务分布式事务处理

每日Java面试场景题知识点之-Spring Boot微服务分布式事务处理

场景问题

在一个电商系统中,用户下单后需要同时完成以下操作:

  1. 订单服务创建订单
  2. 库存服务扣减商品库存
  3. 积分服务增加用户积分
  4. 支付服务处理支付

这些操作分布在不同的微服务中,任何一个步骤失败都需要保证数据的一致性。请问如何设计一个可靠的分布式事务解决方案?

技术栈分析

核心技术组件

  • Spring Boot 2.x+ - 微服务框架
  • Spring Cloud - 微服务治理
  • Seata - 分布式事务中间件
  • Redis - 缓存和分布式锁
  • MySQL - 数据存储
  • RabbitMQ - 消息队列

分布式事务模式选择

常见的分布式事务解决方案有:

  1. 2PC(两阶段提交) - 同步阻塞,性能较差
  2. TCC(Try-Confirm-Cancel) - 业务侵入性强,性能好
  3. Saga模式 - 最终一致性,适合长事务
  4. 本地消息表 - 可靠性高,实现相对简单

解决方案

方案一:Seata AT模式

java 复制代码
@Service
public class OrderServiceImpl implements OrderService {
    
    @GlobalTransactional // Seata全局事务注解
    public OrderResult createOrder(OrderRequest request) {
        // 1. 创建订单
        Order order = orderService.createOrder(request);
        
        // 2. 扣减库存
        inventoryService.deductInventory(request.getItems());
        
        // 3. 增加积分
        pointService.addPoints(request.getUserId(), request.getTotalAmount());
        
        // 4. 处理支付
        paymentService.processPayment(request.getPaymentInfo());
        
        return OrderResult.success(order);
    }
}

配置文件:

yaml 复制代码
seata:
  enabled: true
  application-id: order-service
  tx-service-group: my_test_tx_group
  config:
    type: nacos
    nacos:
      server-addr: localhost:8848
      namespace: seata
      group: SEATA_GROUP
  registry:
    type: nacos
    nacos:
      server-addr: localhost:8848
      namespace: seata
      group: SEATA_GROUP

方案二:TCC模式实现

java 复制代码
@Service
public class InventoryServiceTCC implements InventoryServiceTCC {
    
    @TccTry
    public boolean tryDeductInventory(List<OrderItem> items) {
        // 1. 预扣减库存,冻结资源
        for (OrderItem item : items) {
            boolean result = inventoryRepository.freezeInventory(
                item.getProductId(), item.getQuantity());
            if (!result) {
                return false; // 库存不足
            }
        }
        return true;
    }
    
    @TccConfirm
    public boolean confirmDeductInventory(List<OrderItem> items) {
        // 2. 确认扣减库存,删除冻结记录
        for (OrderItem item : items) {
            inventoryRepository.confirmDeductInventory(
                item.getProductId(), item.getQuantity());
        }
        return true;
    }
    
    @TccCancel
    public boolean cancelDeductInventory(List<OrderItem> items) {
        // 3. 取消扣减,释放冻结库存
        for (OrderItem item : items) {
            inventoryRepository.releaseFrozenInventory(
                item.getProductId(), item.getQuantity());
        }
        return true;
    }
}

方案三:本地消息表 + 事件驱动

java 复制代码
@Service
@Transactional
public class OrderServiceWithEvent {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private MessageEventRepository messageEventRepository;
    
    @Autowired
    private MessagePublisher messagePublisher;
    
    public void createOrder(OrderRequest request) {
        // 1. 创建订单(本地事务)
        Order order = new Order(request);
        orderRepository.save(order);
        
        // 2. 保存待发送的事件消息(本地事务)
        MessageEvent event = new MessageEvent();
        event.setTopic("order_created");
        event.setContent(JSON.toJSONString(order));
        event.setStatus(EventStatus.PENDING);
        messageEventRepository.save(event);
    }
    
    @Scheduled(fixedDelay = 5000)
    public void processPendingEvents() {
        List<MessageEvent> pendingEvents = 
            messageEventRepository.findByStatus(EventStatus.PENDING);
        
        for (MessageEvent event : pendingEvents) {
            try {
                // 发送消息到消息队列
                messagePublisher.publish(event.getTopic(), event.getContent());
                
                // 更新状态为已发送
                event.setStatus(EventStatus.SENT);
                messageEventRepository.save(event);
            } catch (Exception e) {
                // 记录错误,后续重试
                event.setRetryCount(event.getRetryCount() + 1);
                messageEventRepository.save(event);
            }
        }
    }
}

性能优化建议

1. 事务粒度控制

java 复制代码
// 避免大事务,拆分为小事务
@Transactional(propagation = Propagation.REQUIRES_NEW)public void processSingleItem(OrderItem item) {
    // 处理单个订单项
}

2. 异步处理优化

java 复制代码
@Async
public CompletableFuture<Void> processAsync(OrderRequest request) {
    // 异步处理非核心业务
    return CompletableFuture.completedFuture(null);
}

3. 缓存策略

java 复制代码
@Cacheable(value = "inventory", key = "#productId")
public Integer getAvailableInventory(Long productId) {
    return inventoryRepository.getAvailableStock(productId);
}

监控和告警

java 复制代码
@Component
public class TransactionMonitor {
    
    @EventListener
    public void handleTransactionEvent(TransactionEvent event) {
        if (event.getStatus() == TransactionStatus.FAILED) {
            // 发送告警
            alertService.sendAlert("分布式事务失败: " + event.getTxId());
        }
        
        // 记录指标
        metricsCollector.recordTransaction(event.getDuration(), 
            event.getStatus());
    }
}

总结

分布式事务是微服务架构中的核心技术难题,需要根据具体的业务场景选择合适的解决方案:

  1. Seata AT模式:适合对一致性要求较高的场景,实现简单,但性能相对较低
  2. TCC模式:适合性能要求高的场景,但业务侵入性强,实现复杂
  3. 本地消息表:适合最终一致性的场景,可靠性高,易于实现和调试

在实际项目中,建议采用组合策略:核心业务使用强一致性方案,非核心业务使用最终一致性方案,同时建立完善的监控和补偿机制。

感谢读者观看,希望本文对您在Java企业级项目开发中处理分布式事务问题有所帮助!

相关推荐
梦未9 小时前
Spring控制反转与依赖注入
java·后端·spring
喜欢流萤吖~9 小时前
Lambda 表达式
java
ZouZou老师9 小时前
C++设计模式之适配器模式:以家具生产为例
java·设计模式·适配器模式
曼巴UE59 小时前
UE5 C++ 动态多播
java·开发语言
VX:Fegn08959 小时前
计算机毕业设计|基于springboot + vue音乐管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
程序员鱼皮9 小时前
刚刚,IDEA 免费版发布!终于不用破解了
java·程序员·jetbrains
Hui Baby10 小时前
Nacos容灾俩种方案对比
java
曲莫终10 小时前
Java单元测试框架Junit5用法一览
java
成富10 小时前
Chat Agent UI,类似 ChatGPT 的聊天界面,Spring AI 应用的测试工具
java·人工智能·spring·ui·chatgpt