Seata入门系列【2】Spring Cloud 2021.0.5集成seata 1.7.1

1 引出分布式事务问题

1.1 seata-service-account编写查询用户、远程调用下订单接口

@RestController
@RequestMapping("/accountTbl")
public class AccountTblController {

    @Autowired
    AccountTblMapper accountTblMapper;
    @Autowired
    OrderFeign orderFeign;


    @GetMapping("/insertOrder")
    public Object insertOrder() {
        // 查询用户
        AccountTbl accountTbl = accountTblMapper.selectById("11111111");
        // 下单
        Object order = orderFeign.insertOrder(accountTbl.getUserId(), "iphone11", 1, 1);
        // 修改余额
        accountTbl.setMoney(accountTbl.getMoney() - 1);
        accountTblMapper.updateById(accountTbl);
        return order;
    }
}

@FeignClient(name = "seata-service-order")
public interface OrderFeign {

    @GetMapping("orderTbl/insertOrder")
    Object insertOrder(@RequestParam String userId,@RequestParam  String commodityCode,@RequestParam  int count,@RequestParam  int money);
}

1.2 seata-service-order编写下订单,远程调用减库存接口

@RestController
@RequestMapping("/orderTbl")
public class OrderTblController {
    @Autowired
    OrderTblMapper orderTblMapper;
    @Autowired
    StorageFeign storageFeign;

    @GetMapping("insertOrder")
    public Object insertOrder(String userId, String commodityCode, int count, int money) {
        // 下定单
        OrderTbl orderTbl = new OrderTbl();
        orderTbl.setUserId(userId);
        orderTbl.setCommodityCode(commodityCode);
        orderTbl.setCount(count);
        orderTbl.setMoney(1);
        // 下订单扣库存
        orderTblMapper.insert(orderTbl);
        Object storage = storageFeign.updateStorage(commodityCode, count);
        return orderTbl;
    }
}

@FeignClient(name = "seata-service-storage")
public interface StorageFeign {
    @GetMapping("/storageTbl/updateStorage")
    Object updateStorage(@RequestParam String commodityCode,@RequestParam  int count);
}

1.3 seata-service-storage编写减库存接口

@RestController
@RequestMapping("/storageTbl")
public class StorageTblController {
    @Autowired
    StorageTblMapper storageTblMapper;

    @GetMapping("updateStorage")
    Object updateStorage(String commodityCode, int count){
        // 查询库存
        StorageTbl storageTbl = storageTblMapper.selectOne(new LambdaQueryWrapper<StorageTbl>().eq(StorageTbl::getCommodityCode, commodityCode));
        // 减去库存更新
        storageTbl.setCount(storageTbl.getCount()-count);
        int i = storageTblMapper.updateById(storageTbl);
        return storageTbl;
    }
}

1.4 引出分布式事务

当我们关闭seata-service-storage服务,访问/accountTbl/insertOrder接口,会发现下单成功了,但是未扣库存,所以需要引入分布式事务,对一些跨服务的改库操作进行全局管理

2 集成Seata解决分布式事务问题

2.1 各个数据据添加undo_log表

CREATE TABLE `undo_log` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `branch_id` bigint NOT NULL,
  `xid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `context` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

2.2 父pom添加seata依赖

        <dependency>
            <groupId>io.seatagroupId>
            <artifactId>seata-spring-boot-starterartifactId>
            <version>1.6.1version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibabagroupId>
                    <artifactId>druidartifactId>
                exclusion>
            exclusions>
        dependency>
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-seataartifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.seatagroupId>
                    <artifactId>seata-spring-boot-starterartifactId>
                exclusion>
            exclusions>
        dependency>

2.3 各模块添加yml配置

seata:
  enabled: true
  application-id: seata-service-account # 添加为服务名
  tx-service-group: my_test_tx_group
  config:
    type: nacos
    nacos:
      namespace:
      serverAddr: 127.0.0.1:8848
      group: SEATA_GROUP
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
      namespace:

2.4 调用链开端AccountTblController接口添加@GlobalTransactional注解

Seata入门系列【2】Spring Cloud 2021.0.5集成seata 1.7.1_第1张图片

2.5 手动实现xid传递

手动实现xid传递,实际cloud alibaba通过已实现了自动传递,但是新版openfeign移除了很多组件,需要自己实现,添加配置类,并重新去掉自动配置

/**
 * @author wuKeFan
 * @date 2020/11/27
 */
@Component
@ConditionalOnClass({RequestInterceptor.class, GlobalTransactional.class})
public class SeataRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate template) {
        String currentXid = RootContext.getXID();
        if (StrUtil.isNotBlank(currentXid) && !template.url().startsWith(Auth.CHECK_TOKEN_URI) && !template.url().startsWith(Auth.CHECK_RBAC_URI)) {
            template.header(RootContext.KEY_XID, currentXid);
        }
    }
}
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SeataHandlerInterceptor()).addPathPatterns("/**");
    }
}
@SpringBootApplication(exclude = {SeataFeignClientAutoConfiguration.class})

2.6 启动各个项目,访问接口,全局事务提交成功

Seata入门系列【2】Spring Cloud 2021.0.5集成seata 1.7.1_第2张图片

2.7 模拟异常

Seata入门系列【2】Spring Cloud 2021.0.5集成seata 1.7.1_第3张图片
当账户因为异常回滚后,并没有订单及库存数据不一致,全局事务回滚

你可能感兴趣的:(seata,微服务,spring,cloud,后端,seata,微服务,分布式事务)