美文网首页
微服务 15: Seata AT模式 核心代码(文末有项目连接)

微服务 15: Seata AT模式 核心代码(文末有项目连接)

作者: _River_ | 来源:发表于2021-04-17 22:55 被阅读0次
文章知识来源主要来源于:赵俊夫先生的博客  以下为原文链接
https://blog.csdn.net/u011177064/category_9572944.html

seata官方文档:
http://seata.io/zh-cn/docs/overview/what-is-seata.html
1:为什么选择AT模式
经过介绍对AT模式的优缺点都很明显。
优点:
    1:完全没有代码嵌入 使用简单粗暴
    2:通过加锁的方式,可以保证分布式事务的强一致性。

缺点:由于数据库加锁太多 导致高并发场景下效率偏低

对于:普通公司的业务区场景已经是完全够用了
2:Seata 的AT模式 下载资源
使用官方Demo
https://github.com/seata/seata-samples/tree/master/springboot-mybatis

如果下载单个Demo模块的文件:
 
 1:进入网站 http://kinolien.github.io/gitzip/?

2:第一次使用需要Github秘钥
    如何获取Github API Accsess token
    Github->Settings->Developer settings -> Personal accss tokens 
    ghp_pEumyQ5cGgpWkfHXHuDVmUR6JoWQGt0qiXXX

3:输入  https://github.com/seata/seata-samples 
    点击 Search 下载 

下载seata服务端
从 https://github.com/seata/seata/releases,下载服务器软件包,将其解压缩。

点击 seata/bin/ 下的 seata-server.bat 进行启动
启动端口 8091  (window上找不到修改的方法)
Usage: sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for windows) [options]
 Options:
   --host, -h
     The host to bind.
     Default: 0.0.0.0
   --port, -p
     The port to listen.
     Default: 8091
   --storeMode, -m
     log store mode : file、db
     Default: file
   --help 
e.g.
3:初始化分布式数据库SQL

# Storage
DROP SCHEMA IF EXISTS db_storage;
CREATE SCHEMA db_storage;
USE db_storage;

CREATE TABLE `storage_tbl`
(
    `id`             INT(11) NOT NULL AUTO_INCREMENT,
    `commodity_code` VARCHAR(255) DEFAULT NULL,
    `count`          INT(11)      DEFAULT '0',
    PRIMARY KEY (`id`),
    UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;


INSERT INTO storage_tbl (id, commodity_code, count)
VALUES (1, '2001', 1000);

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

# Order
DROP SCHEMA IF EXISTS db_order;
CREATE SCHEMA db_order;
USE db_order;

CREATE TABLE `order_tbl`
(
    `id`             INT(11) NOT NULL AUTO_INCREMENT,
    `user_id`        VARCHAR(255) DEFAULT NULL,
    `commodity_code` VARCHAR(255) DEFAULT NULL,
    `count`          INT(11)      DEFAULT '0',
    `money`          INT(11)      DEFAULT '0',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

4:代码编写 Pom新增Maven包
除 Feign服务 其他所有服务新增以下包
1:需要使用mysql作为持久化数据库 mybatis作为持久化ORM框架
2:引入seata 相关包
        <!-- Mysql 驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.44</version>
        </dependency>
 <!--        连接Mybatis持久层框架-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <!-- Mybatis 驱动包 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>
<!--        seata分布式事务-->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-all</artifactId>
            <version>1.4.0</version>
        </dependency>
5:代码编写 yml新增配置
Feign服务 其他所有服务 yml新增以下配置

实际上:config 与 registry   也能在\seata\conf 下的 registry.conf进行配置
registry.conf 实际上可以和nacos 等服务注册发现中心配合使用
这里为了方便 把config 与 registry 设置为 file类型

相应的存储文件存放在 \seata\bin\sessionStore 的下  root.data
seata:
  enabled: true
  application-id: nacos-consumer
  tx-service-group: my_test_tx_group
  service:
    vgroup-mapping:
      my_test_tx_group: default
    grouplist:
      default: 127.0.0.1:8091

  config:
    type: file

  registry:
    type: file

6:修改service-consumer-demo 服务
Seata 的事务上下文由 RootContext 来管理。
应用开启一个全局事务后,RootContext 会自动绑定该事务的 XID,
事务结束(提交或回滚完成),RootContext 会自动解绑 XID。
该XID为1个分布式事务标识。

seata文档
http://seata.io/zh-cn/docs/user/microservice.html    

XID 192.168.137.1:8091:126826542571458560 

1:外部请求进来   由于使用了@GlobalTransactional注解  获取XID
2:拦截器 在进行Feign调用的时候  如果XID存在 则打印一下  
3:拦截器 在进行Feign调用的时候  把XID(不管是否存在)存放到到请求头

注意:
RootContext.getXID() 只是为了打印一下  而不是生成
@Service
@Slf4j
public class BusinessServiceImpl implements BusinessService {

    @Autowired
    StorageFeignClientService storageFeignClientService;

    @Autowired
    ProviderFeignClientService providerFeignClientService;

    /**
     * 通过 storageFeignClientService 调用 storage服务 进行库存的减少
     * 通过 providerFeignClientService 调用 provider服务 进行订单的新增
     *
     * @param userId
     * @param commodityCode
     * @param orderCount
     */
    @Override
    @GlobalTransactional(rollbackFor = RuntimeException.class)
    public void purchase(String userId, String commodityCode, Integer orderCount) {
        //为了与日志区分 使用 System打印日志

       System.out.println("进入purchase 购买下单,模拟全局事务提交 请求");
        System.out.println("order XID " + RootContext.getXID());

        //storageService服务  db_storage库  storage_tbl表
        storageFeignClientService.seatadeductStorage(commodityCode, orderCount);
        //providerService服务   db_order库  order_tbl表
        providerFeignClientService.seataCreateOrder(userId, commodityCode, orderCount);
    }
}
/**
 * seata 的 AT 模式的 标志 存放到请求头里面
 * HeSuiJin
 */
@Configuration
public class FeignInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        String xid = RootContext.getXID();
        if (StringUtils.isNotBlank(xid)) {
            System.out.println("feign xid:"+xid);
        }
        requestTemplate.header(RootContext.KEY_XID, xid);
    }
}
7:新增服务 service-storage-demo
该服务和 service-provider-demo 的结构一致 

新增接口 /seataTest/deductStorage

被storage-feign调用 进行库存的减少逻辑
storageService服务  db_storage库  storage_tbl表
8:修改service-provider-demo 服务
新增接口 /seataTest/createOrder

被provider-feign调用 进行订单的新增逻辑
providerService服务   db_order库  order_tbl表
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    /**
     * 创建订单
     * @param userId
     * @param commodityCode
     * @param orderCount
     */
    @Override
    public void createOrder(String userId, String commodityCode, Integer orderCount) {
        BigDecimal orderMoney = new BigDecimal(orderCount).multiply(new BigDecimal(5));
        Order order = new Order();
        order.setUserId(userId);
        order.setCommodityCode(commodityCode);
        order.setCount(orderCount);
        order.setMoney(orderMoney);
        orderMapper.insert(order);

        //先进 storage服务 执行完逻辑
        //后进 provider服务 使得产生RuntimeException异常
        //storage服务 和 provider服务 都回滚
        if (true) {
            throw new RuntimeException("provider service  createOrder exception");
        }
    }
}

项目连接

请配合项目代码食用效果更佳:
项目地址:
https://github.com/hesuijin/spring-cloud-alibaba-project
Git下载地址:
https://github.com.cnpmjs.org/hesuijin/spring-cloud-alibaba-project.git

https://github.com/hesuijin/spring-cloud-alibaba-project
Git下载地址:
https://github.com.cnpmjs.org/hesuijin/spring-cloud-alibaba-project.git


在service-storage-demo 模块下   
在service-consumer-demo 模块下
在service-provider-demo 模块下   
在service-provider-demo-other 模块下

相关文章

网友评论

      本文标题:微服务 15: Seata AT模式 核心代码(文末有项目连接)

      本文链接:https://www.haomeiwen.com/subject/kxtslltx.html