每日Java面试场景题知识点之-Spring Boot微服务分布式事务处理
场景问题
在一个电商系统中,用户下单后需要同时完成以下操作:
- 订单服务创建订单
- 库存服务扣减商品库存
- 积分服务增加用户积分
- 支付服务处理支付
这些操作分布在不同的微服务中,任何一个步骤失败都需要保证数据的一致性。请问如何设计一个可靠的分布式事务解决方案?
技术栈分析
核心技术组件
- Spring Boot 2.x+ - 微服务框架
- Spring Cloud - 微服务治理
- Seata - 分布式事务中间件
- Redis - 缓存和分布式锁
- MySQL - 数据存储
- RabbitMQ - 消息队列
分布式事务模式选择
常见的分布式事务解决方案有:
- 2PC(两阶段提交) - 同步阻塞,性能较差
- TCC(Try-Confirm-Cancel) - 业务侵入性强,性能好
- Saga模式 - 最终一致性,适合长事务
- 本地消息表 - 可靠性高,实现相对简单
解决方案
方案一: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());
}
}
总结
分布式事务是微服务架构中的核心技术难题,需要根据具体的业务场景选择合适的解决方案:
- Seata AT模式:适合对一致性要求较高的场景,实现简单,但性能相对较低
- TCC模式:适合性能要求高的场景,但业务侵入性强,实现复杂
- 本地消息表:适合最终一致性的场景,可靠性高,易于实现和调试
在实际项目中,建议采用组合策略:核心业务使用强一致性方案,非核心业务使用最终一致性方案,同时建立完善的监控和补偿机制。
感谢读者观看,希望本文对您在Java企业级项目开发中处理分布式事务问题有所帮助!