04、Seata实战:SpringCloud2020.0.1集成Seata1.4

引出分布式事务问题

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、 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、 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、 访问http://localhost:10000/accountTbl/insertOrder,查看整个流程;
2、 关闭seata-service-storage,访问接口,发现下程序报错,但是依然下单成功,库存未减,出现数据不一致问题;

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

1、 各个数据据添加undo_log表;

-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS undo_log
(
    branch_id     BIGINT(20)   NOT NULL COMMENT 'branch transaction id',
    xid           VARCHAR(100) NOT NULL COMMENT 'global transaction id',
    context       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    rollback_info LONGBLOB     NOT NULL COMMENT 'rollback info',
    log_status    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    log_created   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    log_modified  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY ux_undo_log (xid, branch_id)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

1、 父pom添加seata依赖;

        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.4.0</version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba</groupId>
                    <artifactId>druid</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

1、 各模块添加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:

1、 调用链开端AccountTblController接口添加@GlobalTransactional注解;
*
2、 手动实现xid传递,实际cloudalibaba通过已实现了自动传递,但是新版openfeign移除了很多组件,需要自己实现,添加配置类,并重新去掉自动配置;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import io.seata.core.context.RootContext;
import org.springframework.context.annotation.Configuration;

/**
 * Created by TD on 2021/2/4
 */
@Configuration
public class SeataFeignInterceptor  implements RequestInterceptor {
   
     

    @Override
    public void apply(RequestTemplate requestTemplate) {
   
     
        requestTemplate.header(RootContext.KEY_XID, RootContext.getXID());
    }
}
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
   
     
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
   
     
        registry.addInterceptor(new SeataHandlerInterceptor()).addPathPatterns("/**");
    }
}

@SpringBootApplication(exclude = {
   
     SeataFeignClientAutoConfiguration.class})

1、 启动各个项目,访问接口,全局事务提交成功;
*
2、 模拟异常;
*
3、 当账户因为异常回滚后,并没有订单及库存数据不一致,全局事务回滚;
*

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: