【分布式事务系列】Spring Cloud集成Seata 实现分布式事务(一)

234 阅读2分钟

这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

订单服务、账户服务、库存服务三个微服务之间的整体架构图如下所示,用户执行下单请求时,会调用下单业务的REST接口,接口会分别调用库存服务和订单服务,订单服务还会调用账户服务先进行资金冻结,整个流程涉及到这三个服务的分布式事务问题。

image-20211110220528709.png

环境准备

  • order-service-订单服务
  • repo-service-库存服务
  • account-service-账户服务
  • common-seata-公共服务
  • rest-web-提供统一业务的REST接口服务

order-service、repo-service、account-service是基于SpringBoot+Nacos+Spring Cloud+Mybatis构建的微服务,common-seata提供公共组件,rest-web提供统一业务服务入口。

数据库环境准备

创建三个数据库:seata_order、seata_repo、seata_account,分别在这三个数据库中创建对应的业务表

# seata_orders数据库
CREATE TABLE 'order'(
'id' int(11) NOT NULL AUTO_INCREMENT,
'order_id' varchar(255) DEFAULT NULL,
'user_id' varchar(255) DEFAULT NULL,
'product_code' varchar(255) DEFAULT NULL,
'count' int(11) DEFAULT 0,
'amount' int(11) DEAULT 0,
PRIMARY KEY('id')
)ENGINE=InnoDB DEFAULT CHARSET = utf8;


CREATE TABLE repo(
    id INT(11) NOT NULL AUTO_INCREMENT  COMMENT '' ,
    product_code VARCHAR(255)    COMMENT '' ,
    name VARCHAR(255)    COMMENT '' ,
    count INT(11)    DEFAULT  0 COMMENT '' ,
    PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET = utf8;

CREATE TABLE account(
    id INT(11) NOT NULL AUTO_INCREMENT  COMMENT '' ,
    user_id VARCHAR(255)    COMMENT '' ,
    balance INT(11)    DEFAULT  0 COMMENT '' ,
    PRIMARY KEY (id)
)  ENGINE=InnoDB DEFAULT CHARSET = utf8;

order-service、repo-service、account-service这三个服务需要集成Mybatis,用于和数据库交互。

account-service账户服务提供余额扣减功能,具体核心代码如下:

@Slf4j
@Service
public class AccountServiceImpl implements IAccountService{
 @Autowired
 private AccountMapper accountMapper;
 @Override
 public AjaxResult descreaseAccount(AccountDto accountDto){
     int num = 0;
 	try{
		 	 num = accountMapper.descreaseAccount(accountDto.getUserId(),accountDto.getBalance().doubleValue());
       
 	}catch(Exception e){
        log.error("余额扣减异常:{}",e);
    }
     if(num>0){
            return AjaxResult.success();
        }else{
            return AjaxResult.error();
        }
 }
}

order-service订单服务负责创建订单,在创建订单之前先调用账户服务的余额扣减接口

@Slf4j
@Service
public class OrderServiceImpl implements IOrderService{
	@Autowired
    private OrderMapper orderMapper;
    @Autowired
    private IAccountService accountService;
    @Autowired
    private OrderConvert orderConvert;
    @Override
    public AjaxResult createOrder(OrderDto orderDto){
        try{
            AccountDto accountDto=new AccountDto();
            accountDto.setUserid(orderDto.getUserId());
            accountDto.setBalance(orderDto.getOrderAmount());
            AjaxResult ajaxResult = accountService.decreaseAccount(accountDto);
            Order order = orderConvert.createOrder(orderDto);
            order.setOrderNo(UUID.randomUUID().toString());
            orderMapper.createOrder(order);
            if(ajaxResult.getCode() != ResultCode.SUCCESS.getCode()){
                return AjaxResult.error();
            }
            return AjaxResult.success();
        }catch(Exception e){
           log.error("创建订单异常:{}",e);                   
        }
    }
    
}