这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战
订单服务、账户服务、库存服务三个微服务之间的整体架构图如下所示,用户执行下单请求时,会调用下单业务的REST接口,接口会分别调用库存服务和订单服务,订单服务还会调用账户服务先进行资金冻结,整个流程涉及到这三个服务的分布式事务问题。
环境准备
- 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);
}
}
}