SpringCloud Alibaba之Seata分布式事务学习笔记(下)

举报
长路 发表于 2022/11/28 20:14:32 2022/11/28
【摘要】 Gitee仓库、Github仓库博客目录索引(持续更新)SpringCloud 教程 已完结(IDEA 2022.1最新版)4K蓝光画质 微服务开发PS:本章节中部分图片是直接引用学习课程课件,如有侵权,请联系删除。、、。SpringCloud Alibaba为我们提供了用于处理分布式事务的组件Seata。Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Se

2.2.2、服务集成seata组件实现全局分布式事务

image-20220803134423122

三个服务都进行集成seata依赖,主要配置步骤如下

1、引入seata依赖:

<!--    引入seata依赖    -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

2、配置文件来添加seata配置项,下面给出三个服务的不同配置项,下面需要特别注意的就是黄线的部分需要根据不同的服务名来进行配置:

image-20220803134634743

seata-user-service:

seata:
  service:
    vgroup-mapping:
      # 这里需要对事务组做映射,默认的分组名为 应用名称-seata-service-group,将其映射到default集群
      # 这个很关键,一定要配置对,不然会找不到服务
      user-service-seata-service-group: default
    grouplist:
      default: localhost:8868

seata-book-service:

seata:
  service:
    vgroup-mapping:
        # 这里需要对事务组做映射,默认的分组名为 应用名称-seata-service-group,将其映射到default集群
        # 这个很关键,一定要配置对,不然会找不到服务
      book-service-seata-service-group: default
    grouplist:
      default: localhost:8868

seata-borrow-service:

seata:
  service:
    vgroup-mapping:
      # 这里需要对事务组做映射,默认的分组名为 应用名称-seata-service-group,将其映射到default集群
      # 这个很关键,一定要配置对,不然会找不到服务
      borrow-service-seata-service-group: default
    grouplist:
      default: localhost:8868

3、三个服务的启动器都去开启seata事务注解:

@EnableAutoDataSourceProxy //开启seata事务配置

4、在本地数据库中创建undo_log日志表

  • 由于三个服务都使用的一个数据库seata-demo,所以我们直接在一个数据库中创建即可
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;

5、最终在我们要进行分布式事务的service方法中添加全局事务注解!也就是borrow-service服务中的borrow()方法:

@GlobalTransactional

image-20220803135518838


2.2.3、测试

提前准备

首先将seata-server服务器启动。

接着启动我们的三个服务:在启动时向seata-server去进行注册

image-20220803140013883

看下seata-server服务的控制台:可以看到确实三个服务已经注册成功了

image-20220803140125457

开始测试

首先来进行测试:http://localhost:8082/borrow/1/2

image-20220803140319554

第一次借阅是没有问题的,看下数据库:

image-20220803140351927 image-20220803140401585 image-20220803140411020

再次来进行借阅下:

image-20220803140431224

ok,此时再看下数据库的各个表:原本在book表中产生问题的数据在这里就没有再出现了,可以看到中间出现异常能够成功回滚了

image-20220803140453579 image-20220803140501903 image-20220803140510317


debug

我们在修改、删除操作上进行debug:

image-20220803140907757

看下undo_log表:

image-20220803140940093

扣减步骤完成后执行下一步:

image-20220803140954431

再次看下undo_log表:

image-20220803141055346

其中包含一个全局唯一xid:全局事务就是根据这一条记录来进行回滚管理的!


2.3、采用nacos模式服务

对于项目中引入依赖以及添加注解相关操作间2.2.2中的配置步骤,这里不再做演示。

2.3.1、配置完整步骤

1、在nacos中创建一个命名空间seata

image-20220803144927861

2、修改配置文件

registry.conf:

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sof
  type = "nacos"

  nacos {
    # 应用名固定为seata-server
    application = "seata-server"
    # 注册中心的地址
    serverAddr = "127.0.0.1:8848"
    # 默认
    group = "SEATA_GROUP"
    # 命名空间的id
    namespace = "c30eb1d8-8e49-4b5d-beca-b1bf9479e94a"
    # 默认
    cluster = "default"
    # 连接用户名与密码
    username = "nacos"
    password = "nacos"
  }
}
  
config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = "c30eb1d8-8e49-4b5d-beca-b1bf9479e94a"
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
    dataId = "seataServer.properties"
  }
}

3、下载develop包,执行其中的script中脚本来对nacos的配置中心中seata命名空间配置项进行初始化:

下载地址:seata开发包

链接:https://pan.baidu.com/s/1iiQphUPbvgcIyXcIjUcjZA 
提取码:cbr2 

进入到其中nacos目录下执行脚本,在windows中我们使用git工具来使用:

image-20220803144519570

./nacos-config-interactive.sh

image-20220803143051403

最终效果如下:

image-20220803161712312

4、手动在命名空间seata中添加三个服务的配置项:

image-20220803145654882

service.vgroupMapping.user-service-seata-service-group   SEATA_GROUP   default
service.vgroupMapping.book-service-seata-service-group  SEATA_GROUP  default
service.vgroupMapping.borrow-service-seata-service-group  SEATA_GROUP  default

5、在三个服务项目中的各个服务添加配置项(替换之前的file模式):

# 2、nacos模式
seata:
  # 注册
  registry:
    # 使用Nacos
    type: nacos
    nacos:
      # 使用Seata的命名空间,这样才能正确找到Seata服务,由于组使用的是SEATA_GROUP,配置默认值就是,就不用配了
      namespace: c30eb1d8-8e49-4b5d-beca-b1bf9479e94a
      username: nacos
      password: nacos
  # 配置
  config:
    type: nacos
    nacos:
      namespace: c30eb1d8-8e49-4b5d-beca-b1bf9479e94a
      username: nacos
      password: nacos

6、关于nacos-server的会话存储位置(默认是file)

此时注册和配置相关的会话都继承在Nacos中进行了

还可以配置一下事务会话信息的存储方式,默认是file类型,那么就会在运行目录下创建file_store目录,可以看下启动seata-server后创建的文件效果:

image-20220803150635786

6.1、其实我们可以将其搬到数据库中存储,只需要修改一下配置即可,在seata的命名空间中进行修改配置内容如下:

  • 1、修改两个配置:store.session.mode、``store.mode的值为db`
  • 2、接着我们对数据库信息进行一下配置:
    • 数据库驱动(8.0的需要修改):com.mysql.cj.jdbc.Driver
    • 数据库URL:默认就是seata数据库就好。
    • 数据库用户名密码:store.db.userstore.db.password

6.2、创建一个数据库【seata】:

image-20220803151707925

-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(255),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `status`         TINYINT      NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_status` (`status`),
    KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    primary key (`lock_key`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('HandleAllSession', ' ', 0);

那么配置就已经完成了!


2.3.2、测试

前提准备

启动nacos服务、seata服务如下:

image-20220803162049068

执行seata启动的命令:

seata-server.bat -p 8868

image-20220803162158904

启动三个服务:

image-20220803162323674

与此同时,可以看到在seata服务的控制台中你可以看到里面的服务注册信息:

image-20220803162345887

测试

访问借阅地址:http://localhost:8082/borrow/1/2

image-20220803162724864

再此访问,肯定在中途去判断是否该用户借阅了书阶段出现异常,进行回滚,我们只需要关注book表中的书籍借阅数量有没有-1的问题,其实就是看其有没有回滚:

image-20220803162900990

看下数据库:

image-20220803162923054

没有问题!


2.3.3、debug

在这里我们来进行打上断点:

image-20220803163021273

看看seata数据库以及我们自己本身的数据库undo_log中的记录是否产生变化:

接着来了一个请求,我们看debug的目前阶段:

image-20220803163540694

此时来看数据库的情况:

seata数据库:记录依次是红框从上往下

image-20220803163300534

image-20220803163148348

image-20220803163205472

image-20220803163231371

seata-demo中的undo_log表

image-20220803163140302

可以看到用户表中的xid是依赖于tc也就是seata-server来进行回滚的。


参考资料

[1]. SpringCould笔记(二)微服务进阶 Cloud Alibaba

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。