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

118 阅读2分钟

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

repo-service库存服务提供库存扣减功能

@Slf4j
@Service
public class RepoServiceImpl implements IRepoService{
	@Autowired
    private RepoMapper repoMapper;
    @Override
    public AjaxResult descreaseRepo(ProductDto productDto){
        int num=0;
        try{
           num =  repoMapper.descreaseRepo(productDto.getProductCode(),productDto.getCount());
        }catch(Exception e){
            log.error("扣减库存异常:{}",e);
        }
        if(num > 0){
            return AjaxResult.success();
        }else{
            return AjaxResult.error();
        }
    }
}

rest-web是基于SpringBoot的Web项目,用于对外提供以业务的REST接口,它会分别调用库存服务和订单服务,实现库存扣减及订单创建功能。

@Slf4j
@RestController
public class OrderController{
	@Autowired
    private IRestOrderService restOrderService;
    
    @PostMapping("order")
    public AjaxResult order(@RequestBody OrderDto orderDto) throw Exception{
        return restOrderService.handleBusiness(orderDto);
    }
}

RestOrderServiceImpl的具体实现如下:

@Slf4j
@Service
public class RestOrderServiceImpl implements IRestOrderService{
    @Reference
    private IRepoService repoService;
    @Reference
    private IOrderService orderService;
    
    @Override
    @GlobalTransactional(timeoutMills=300000,name="rest-web")
    public AjaxResult handleBusiness(OrderReq orderReq) throw Exception{
        log.info("开始全局事务:xid={}",RootContext.getIp());
        log.info("开始订单:"+orderReq);
      	ProductDto productDto = new ProductDto();
        productDto.setProductCode(orderReq.getProductCode());
        productDto.setCount(orderReq.getCount());
        AjaxResult ajaxResult = repoService.decreaseRepo(productDto);
		//创建订单
        OrderDto orderDto = new OrderDto();
        orderDto.setUserId(orderReq.getUserId());
        orderDto.setOrderAmount(orderReq.getAmount());
        orderDto.setOrderCount(orderReq.getCount());
        orderDto.setProductCode(orderReq.getProductCode());
        AjaxResult orderResult = orderServce.createOrder(orderDto);
        AjaxResult result = new AjaxResult();
		result.put("data",orderResult.getData());
        return result;
    	}
}

项目彼此之间存在依赖关系,服务与服务之间也有相关的依赖,服务启动顺序:

  1. commom-seata 为公共组件,需要先通过mvn 添加
  2. install 安装本地maven仓库,给其他服务依赖
  3. 启动账户服务account-service,它会被订单服务调用
  4. 启动订单服务order-service
  5. 启动库存服务repo-service
  6. 启动rest-web,作为REST的业务入口。

集成Seata实现分布式事务

在上面的流程中,库存扣减成功了,但是创建订单由于账户资金不足导致失败而出现数据不一致的场景,出现这种情况,需要将被扣减的库存需要加回去,这涉及到一个分布式事务的场景。

添加Seata Jar包依赖

分别在4个服务项目添加Seata的starter组件依赖

<dependency>
	<groupId>io.seata</groupId>
	<artifactId>seata-spring-boot-starter</artifactId>
	<version>1.0.0</version>
</dependency>
添加Seata配置项目

分别在4个服务项目中的application.yml文件添加Seata的配置项。