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

473 阅读2分钟

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

Seata配置有几个配置项需要注意:

  • seata.support.spring.datasource-autoproxy:true属性表示数据源自动代理开关,在order-service、account-service、repo-service中设置为true,在rest-web中设置为false,因为该项目并没有访问数据源,不需要代理
  • 如果注册中心为file,seata.service.grouplist需要填写Seata服务端连接地址,在默认情况下,注册中心为file,如果需要从注册中心上进行服务发现,可增加配置如下:
seata:
  registry:
  	type: nacos
  	nacos:
  	  cluster: default
  	  server-addr: 192.168.216.128:8848
  • tx-service-group表示指定服务所属的事务分组,如果没有执行,默认使用spring.application.name加上-seata-service-group,需要注意这两项配置必须配置一项,否则会报错。

添加回滚日志表

分别在3个数据库seata-account、seata-repo、seata-order中添加一张回滚日志表,用于记录每个数据库表操作的回滚日志,当某个服务的事务出现异常时会根据该日志进行回滚。

CREATE TABLE undo_log(
    id bigint(20) NOT NULL AUTO_INCREMENT  COMMENT '' ,
    branch_id bigint(20)    COMMENT '' ,
    xid VARCHAR(200)    COMMENT '' ,
    context VARCHAR(250)    COMMENT '' ,
    rollback_info longblob    COMMENT '' ,
    log_status int(11)    COMMENT '' ,
    log_created DATETIME    COMMENT '' ,
    log_modified DATETIME    COMMENT '' ,
    PRIMARY KEY (id)
    UNIQUE KEY 'ux_undo_log'('xid,'branch_id')
)ENGINE=InnoDB DEFAULT CHARSET=utf8  COMMENT = '回滚日志表';
rest-web增加全局事务控制

修改rest-web项目的RestOrderServiceImpl,需要做以下两个操作:

  • 增加@GlobalTransactional全局事务注解
  • 模拟一个异常处理,当商品编号等于某个指定的值时抛出异常,触发整个事务的回滚。
@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);
        if(orderReq.getProductCode().equals("20211113")){
            throw new Exception("触发异常");
        }
        AjaxResult result = new AjaxResult();
		result.put("data",orderResult.getData());
        return result;
    	}
}

在异常触发的位置来看,如果没有引入分布式事务,即使出现了异常,由于库存扣减、订单创建、账户资金扣减等操作已经生效,所以数据无法被回滚,而在引入seata后,在异常出现后会触发各个事务分支的数据回滚,保证数据的正确性,如果配置正常,能完成事务回滚操作。