每日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企业级项目开发中处理分布式事务问题有所帮助!

相关推荐
罗超驿8 分钟前
独立实现双向链表_LinkedList
java·数据结构·链表·linkedlist
盐水冰1 小时前
【烘焙坊项目】后端搭建(12) - 订单状态定时处理,来单提醒和顾客催单
java·后端·学习
凸头1 小时前
CompletableFuture 与 Future 对比与实战示例
java·开发语言
wuqingshun3141591 小时前
线程安全需要保证几个基本特征
java·开发语言·jvm
努力也学不会java2 小时前
【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU
java·数据结构·人工智能·算法·缓存·面试
攒了一袋星辰2 小时前
高并发强一致性顺序号生成系统 -- SequenceGenerator
java·数据库·mysql
小涛不学习2 小时前
Spring Boot 详解(从入门到原理)
java·spring boot·后端
于先生吖3 小时前
Java框架开发短剧漫剧系统:后台管理与接口开发
java·开发语言
daidaidaiyu3 小时前
Spring IOC 源码学习 声明式事务的入口点
java·spring
myloveasuka3 小时前
[Java]查找算法&排序算法
java·算法·排序算法