MST
星途 面试题库

面试题:Spring Cloud微服务架构下业务场景中的分布式事务处理

在一个复杂的Spring Cloud微服务架构电商场景中,涉及订单服务、库存服务、支付服务等多个微服务。当用户下单时,需要保证订单创建、库存扣减和支付这一系列操作要么全部成功,要么全部失败。请详细说明如何基于Spring Cloud Alibaba的Seata框架来设计并实现分布式事务解决方案,包括Seata的核心组件(TC、TM、RM)在这个场景中的具体作用,以及相关的配置和代码实现要点。
28.1万 热度难度
后端开发微服务架构

知识考点

AI 面试

面试题答案

一键面试

1. Seata核心组件在该场景中的作用

  • TC(Transaction Coordinator):事务协调者,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。在电商下单场景中,TC会记录订单创建、库存扣减、支付这一系列操作组成的全局事务的状态。当所有分支事务都成功准备好后,TC会通知各分支事务提交;若有任何一个分支事务失败,TC会通知所有分支事务回滚。
  • TM(Transaction Manager):事务管理器,定义全局事务的范围,开始全局事务、提交或回滚全局事务。在用户下单场景中,订单服务扮演TM的角色。订单服务首先开启一个全局事务,在订单创建、库存扣减、支付等操作完成后,根据各操作的结果决定是提交还是回滚全局事务。
  • RM(Resource Manager):资源管理器,管理分支事务处理的资源,与TC进行通信,汇报分支事务的状态,并接收TC的指令,执行分支事务的提交或回滚。库存服务和支付服务是RM。库存服务在扣减库存时作为一个分支事务,向TC汇报扣减库存操作的状态,并根据TC的指令决定是否提交或回滚库存扣减操作;支付服务同理,汇报支付操作状态并按指令行事。

2. 配置要点

  • 引入依赖:在各个微服务(订单、库存、支付服务)的pom.xml中引入Seata相关依赖。例如:
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.4.2</version>
</dependency>
  • 配置文件
    • 在每个微服务的application.yml中配置Seata相关参数。
    seata:
      application-id: ${spring.application.name}
      tx-service-group: my_test_tx_group
    
    • 配置Seata Server地址,在registry.conf中配置:
    registry {
      type = "nacos"
      nacos {
        serverAddr = "127.0.0.1:8848"
        namespace = ""
        group = "SEATA_GROUP"
        application = "seata-server"
        dataId = "seataServer.properties"
        username = "nacos"
        password = "nacos"
      }
    }
    
    config {
      type = "nacos"
      nacos {
        serverAddr = "127.0.0.1:8848"
        namespace = ""
        group = "SEATA_GROUP"
        dataId = "seataServer.properties"
        username = "nacos"
        password = "nacos"
      }
    }
    
    • 在Nacos中配置Seata的事务分组与TC的映射关系,在seataServer.properties中添加:
    service.vgroupMapping.my_test_tx_group=default
    
  • 数据源代理:在每个微服务中配置数据源代理,将原有的数据源替换为Seata的DataSourceAutoConfiguration配置的代理数据源。例如在订单服务的application.yml中:
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/order_db
    username: root
    password: root

并在SeataAutoConfiguration类中:

import com.alibaba.druid.pool.DruidDataSource;
import io.seata.spring.boot.autoconfigure.SeataDataSourceAutoConfiguration;
import io.seata.spring.boot.autoconfigure.SeataProperties;
import io.seata.spring.boot.autoconfigure.SeataProperties.DataSource;
import io.seata.spring.boot.autoconfigure.SeataProperties.TxServiceGroup;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Database;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Driver;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.JdbcUrl;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.User;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Password;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.Xa;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.At;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.Tcc;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.Saga;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaRecovery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtRecovery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccRecovery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaRecovery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchRegister;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchRegister;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchRegister;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchRegister;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchUnregister;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchUnregister;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchUnregister;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchUnregister;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchRetryCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchRetryCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchRetryCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchRetryCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchRetryRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchRetryRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchRetryRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchRetryRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchRetryStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchRetryStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchRetryStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchRetryStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchRetryLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchRetryLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchRetryLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchRetryLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoRetryCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoRetryCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoRetryCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoRetryCommit;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoRetryRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoRetryRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoRetryRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoRetryRollback;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoRetryStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoRetryStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoRetryStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoRetryStatusQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoRetryLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoRetryLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoRetryLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoRetryLockQuery;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoCommitOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoCommitOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoCommitOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoCommitOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoRollbackOnFailure;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoRollbackOnFailure;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoRollbackOnFailure;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoRollbackOnFailure;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoStatusQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoStatusQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoStatusQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoStatusQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoLockQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoLockQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoLockQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoLockQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoRetryCommitOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoRetryCommitOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoRetryCommitOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoRetryCommitOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoRetryRollbackOnFailure;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoRetryRollbackOnFailure;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoRetryRollbackOnFailure;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoRetryRollbackOnFailure;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoRetryStatusQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoRetryStatusQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoRetryStatusQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoRetryStatusQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.XaBranchAutoRetryLockQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.AtBranchAutoRetryLockQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.TccBranchAutoRetryLockQueryOnSuccess;
import io.seata.spring.boot.autoconfigure.SeataProperties.XaDataSource.Schema.Mode.SagaBranchAutoRetryLockQueryOnSuccess;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class SeataAutoConfiguration {

    @Bean
    @Primary
    public DataSource dataSource(DataSourceProperties properties) {
        DruidDataSource druidDataSource = properties.initializeDataSourceBuilder().type(DruidDataSource.class).build();
        return new io.seata.spring.boot.autoconfigure.SeataDataSourceAutoConfiguration.SeataAutoDataSource(druidDataSource);
    }
}

3. 代码实现要点

  • 订单服务(TM)
    import io.seata.spring.annotation.GlobalTransactional;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class OrderService {
    
        @Autowired
        private InventoryService inventoryService;
        @Autowired
        private PaymentService paymentService;
    
        @GlobalTransactional(name = "order-create-tx", rollbackFor = Exception.class)
        @Transactional
        public void createOrder(Order order) {
            // 创建订单
            create(order);
            // 调用库存服务扣减库存
            inventoryService.decrease(order.getProductId(), order.getQuantity());
            // 调用支付服务进行支付
            paymentService.pay(order.getUserId(), order.getTotalAmount());
        }
    
        private void create(Order order) {
            // 订单创建逻辑,向数据库插入订单数据
        }
    }
    
  • 库存服务(RM)
    import io.seata.spring.annotation.GlobalLock;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class InventoryService {
    
        @GlobalLock
        @Transactional
        public void decrease(Long productId, Integer quantity) {
            // 扣减库存逻辑,更新数据库库存数据
        }
    }
    
  • 支付服务(RM)
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class PaymentService {
    
        @Transactional
        public void pay(Long userId, BigDecimal amount) {
            // 支付逻辑,更新数据库支付记录等
        }
    }
    

通过以上Seata框架的设计、配置与代码实现,即可在Spring Cloud Alibaba微服务架构电商场景中实现分布式事务,保证订单创建、库存扣减和支付操作的一致性。