17-Ali-Seata

本笔记来源于:尚硅谷SpringCloud框架开发教程(SpringCloudAlibaba微服务分布式架构丨Spring Cloud)
b站视频
文章来自:
https://github.com/OT-mt/cloud2020/tree/master/springcloud-2%E5%B0%9A%E7%A1%85%E8%B0%B7%E5%91%A8%E9%98%B3-2020

脑图

本地:
尚硅谷SpringCloud

在线:
尚硅谷SpringCloud

简介

解决问题

  1. 分布式前Java服务与数据库1->1
  2. 分布式后 1->1,1>多,多->多
    保证多个服务之间的数据一致性

    是什么

    Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

    官网

    http://seata.io/zh-cn/

    处理过程

一ID+三组件
  1. id
    全局唯一的事务ID
  2. 3组件
    1. TC - 事务协调者
      维护全局和分支事务的状态,驱动全局事务提交或回滚。
    2. TM - 事务管理器
      定义全局事务的范围:开始全局事务、提交或回滚全局事务。
    3. RM - 资源管理器
      管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
      处理过程
  3. TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID
  4. XID在微服务调用链路的上下文中传播
  5. RM向TC注册分支事务,将其纳入XID对应全局事务的管辖
  6. TM 向 TC 发起针对 XID 的全局提交或回滚请求
  7. TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求

安装

  1. 下载
    https://github.com/seata/seata/releases

  2. 找到conf下的 file.conf
    将 mode 改为 db代表将日志存储到数据库
    修改数据库账号密码端口
    找到 register.conf
    将 registry 与 config 里的 type均改为nacos
    同时修改两者下面的 nacos信息

  3. 创建数据库 seata

  4. 数据库加载文件
    查看RANDME.MD server 对应网址即可

    1. https://github.com/seata/seata/tree/develop/script/client下db中的mysql

实验

数据库

  1. 创建数据库
    1. create database seata_order;订单
    2. create database seata_storage;库存
    3. create database seata_account;账户信息
  2. 建表
    1. seata_order下建t_order
    2. seata_storage下建 t_storage;
    3. seata_account下建 t_account
  3. 建表sql
    1
    2
    3
    4
    5
    6
    7
    8
    create table t_order(
    id bigint(11) not null auto_increment primary key,
    user_id bigint(11) default null comment '用户id',
    product_id bigint(11) default null comment '产品id',
    count int(11) default null comment '数量',
    money decimal(11,0) default null comment '余额',
    status int(1) default null comment '订单状态'
    )

    建模块

    seata-order-service2001
  4. pom
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!-- seata -->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-seata</artifactId>
    <exclusions>
    <exclusion>
    <groupId>io.seata</groupId>
    <artifactId>seata-all</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    <!-- 引入与自己版本相同的 -->
    <dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-all</artifactId>
    <version>1.2.0</version>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

##########################

  1. 依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <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>
    <!-- 引入与自己版本相同的 -->
    <dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.2.0</version>
    </dependency>
  2. yml

  3. config.txt nacos-config.sh 上传配置

本例使用seata1.2

创建seata数据库

  1. 找到 seata/conf 下的 README-zh.md
  2. 进入 server
    1. 找到 db 下的 mysql.sql
    2. 创建数据库 seata ,后执行mysql.sql
    3. mysql.sql中的三张表为 seata配置必须的表

      创建业务必须数据库

      用以做案例
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      -- 建数据库,订单
      create database seata_order;
      use seata_order;
      -- 建订单表
      CREATE TABLE `t_order` (
      `id` INT(11) NOT NULL AUTO_INCREMENT,
      `name` VARCHAR(50) NULL DEFAULT NULL,
      PRIMARY KEY (`id`)
      )
      COLLATE='utf8_general_ci'
      ENGINE=InnoDB
      AUTO_INCREMENT=8
      ;
      -- 建数据库,库存
      create database seata_storage;
      -- 建库存表
      CREATE TABLE `t_storage` (
      `id` INT(11) NOT NULL,
      `num` INT(11) NOT NULL,
      PRIMARY KEY (`id`)
      )
      COLLATE='utf8_general_ci'
      ENGINE=InnoDB
      ;
      -- 初始化库存数量
      insert into t_storage values(1,20);
  3. 找到 seata/conf 下的 README-zh.md
  4. 进入 client
  5. 找到db下的mysql.sqlclient
  6. 其中为一建表sql
  7. ==每一个分布式业务数据库都需要这张表,即在新建的数据库 seata_order 与 seata_storage中新建该表==

    修改seata1.2

  8. 找到 seata/conf/file.conf
    将 store 下的 mode 改为 db ,代表采用数据库配置
    更改 store下数据库的相关配置
  9. 找到 seata/conf/registry.conf
    将 type 改为 nacos 同时修改 nacos中的信息和config下nacos的信息
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    registry {
    # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
    type = "nacos"

    nacos {
    application = "seata-server"
    serverAddr = "localhost:8848"
    namespace = ""
    cluster = "default"
    username = "nacos"
    password = "nacos"
    }
    }

    config {
    # file、nacos 、apollo、zk、consul、etcd3
    type = "nacos"

    nacos {
    serverAddr = "localhost:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
    }
    }

    为nacos添加配置信息

  10. 访问 config-center
  11. 将 config.txt 拷贝到 seata/下
  12. 修改config.txt内容为下列,因为其余配置为默认或无用配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    service.vgroupMapping.my_test_tx_group=default
    store.mode=db
    store.db.datasource=druid
    store.db.dbType=mysql
    store.db.driverClassName=com.mysql.jdbc.Driver
    store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true
    store.db.user=root
    store.db.password=root
    store.db.minConn=5
    store.db.maxConn=30
    store.db.globalTable=global_table
    store.db.branchTable=branch_table
    store.db.queryLimit=100
    store.db.lockTable=lock_table
    store.db.maxWait=5000
  13. 将 nacos 下的 nacos-config.sh 拷贝到 seata/conf/ 下
  14. 启动nacos
  15. 使用 Git Bash Here 切换到 seata/conf/ 下执行命令sh nacos-config.sh
  16. 查看nacos中是否有 seata 相关的配置信息。

    配置业务seata-order-service2001

  17. pom
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    <dependencies>
    <!--引入自己的公共api-->
    <dependency>
    <groupId>com.wxh.springcloud</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>${project.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!--热部署-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <!-- 使用openfeign做微服务调用 -->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </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>
    <!-- 引入与自己版本相同的 -->
    <dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.2.0</version>
    </dependency>
    </dependencies>
  18. yml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    # 端口号
    server:
    port: 2001
    spring:
    application:
    name: seata-order-service
    cloud:
    nacos:
    discovery: #Nacos注册中心地址
    server-addr: localhost:8848
    datasource:
    type: com.alibaba.druid.pool.DruidDataSource #数据源类型
    driver-class-name: org.gjt.mm.mysql.Driver #mysql驱动包
    url: jdbc:mysql://localhost:3306/seata_order?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
    feign:
    hystrix:
    enabled: true

    logging:
    level:
    io:
    seata: info
    mybatis:
    mapper-locations: classpath:mapper/*.xml

    seata:
    enabled: true
    # 应用 id 为唯一便于区分
    application-id: order
    # 事务分组,这个是默认分组
    tx-service-group: my_test_tx_group
    config:
    type: nacos
    nacos:
    namespace:
    serverAddr: 127.0.0.1:8848
    group: SEATA_GROUP
    userName: "nacos"
    password: "nacos"
    registry:
    type: nacos
    nacos:
    application: seata-server
    server-addr: 127.0.0.1:8848
    namespace:
    userName: "nacos"
    password: "nacos"

  19. mapper
    1
    2
    3
    4
    5
    6
    @Mapper
    public interface OrderMapper {
    // 插入一条订单
    @Insert("insert into t_order values(null,'test')")
    public void test();
    }
  20. service:接口类省略
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Service
    public class OrderServiceImpl implements OrderService {

    @Resource
    OrderMapper orderMapper;
    @Resource
    StroageService stroageService;

    @Override
    // name对应配置文件里的事务分组
    @GlobalTransactional(name = "my_test_tx_group",rollbackFor = Exception.class)
    public void test() {
    orderMapper.test();
    stroageService.test();
    }
    }
  21. StorageService.java
    1
    2
    3
    4
    5
    @FeignClient(value = "seata-storage-service")
    public interface StroageService {
    @RequestMapping("/test")
    public String test();
    }
  22. controller
    1
    2
    3
    4
    5
    6
    7
    @Resource
    private OrderService orderService;
    @RequestMapping("/test")
    public String test(){
    orderService.test();
    return "test";
    }

    配置业务模块seata-storage-service2003

  23. pom 与上一模块相同
  24. yml 与上一模块相同
    1. 更改端口号
    2. 更改spring.application.name.
    3. 更改seata.application-id: storage
  25. 为了方便省去service由controller直接调用mapper
  26. mapper
    1
    2
    3
    4
    5
    6
    @Mapper
    public interface StorageMapper {
    // 代表库存减1
    @Update("UPDATE t_storage SET num = num-1 WHERE id = 1")
    public void test();
    }
  27. controller
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @RestController
    public class StorageController {
    @Resource
    StorageMapper storageMapper;

    @RequestMapping("/test")
    public String test(){

    // int a = 1/0; // 模拟异常

    storageMapper.test();
    return "storage";
    }
    }

    测试

  28. 正常启动两个模块
  29. 访问http://localhost:2001/test查看是否能成功访问
  30. 启动模拟异常
  31. 将模块 seata-order-service2001 中 OrderServiceImpl.class 下的 stroageService.test();打上断点
  32. debug 启动seata-order-service2001
  33. 访问 http://localhost:2001/test
  34. 此时进入断点
  35. 查看 t_order 表中新增一条数据,数据库中 seata_order 下的 undo_log 表中增加信息,代表事务
  36. 数据库 seata_order 的 undo_log 表中添加事务信息
  37. 结束执行代码
  38. t_order 表中数据消失
  39. 数据库 seata_order 的 undo_log 表数据消失
  40. 测试成功

修改事务分组

  1. yml中
    seata:
    tx-service-group: test
  2. nacos中新增配置
    service.vgroupMapping.test
    内容为 default
  3. service.vgroupMapping.test 的值为集群名称,test即事务分组 ,default代表无集群

17-Ali-Seata
http://yuanql.top/2023/06/27/13_SpringCloud/springcloud-2尚硅谷周阳-2020/17-Ali-Seata/
作者
Qingli Yuan
发布于
2023年6月27日
许可协议