springboot2.x+dubbo2.x+seata1.x AT+nacos+zk实现分布式事务

Seata AT模式接入

目录

一、Seata AT模式介绍... 1

前提... 1

整体机制... 1

写隔离... 1

读隔离... 4

工作机制... 5

一阶段... 5

二阶段-回滚... 7

二阶段-提交... 7

优势:... 7

缺点:... 7

二、Seata AT接入步骤... 7

用例描述... 7

框架组件... 8

配置Seata服务端... 8

1. 下载seata-server插件... 8

2. 配置config.txt. 8

3. 新建logs文件... 9

4. 修改conf/ registry.conf配置... 10

5. 修改conf/ nacos-config.sh文件... 11

6. 执行conf/ nacos-config.sh脚本... 12

7. 启动seata-server服务... 12

配置Seata客户端... 13

服务介绍... 13

mot服务... 15

user-control服务... 21

admin-web服务... 27

三、注意事项... 35

 

 

一、Seata AT模式介绍

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 ATTCCSAGA XA 事务模式,为用户打造一站式的分布式解决方案。本文只讲如何接入AT模式。

前提

  • 基于支持本地 ACID 事务的关系型数据库。
  • Java 应用,通过 JDBC 访问数据库。

整体机制

两阶段提交协议的演变:

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
  • 二阶段:
    • 提交异步化,非常快速地完成。
    • 回滚通过一阶段的回滚日志进行反向补偿。

写隔离

  • 一阶段本地事务提交前,需要确保先拿到 全局锁 
  • 拿不到 全局锁 ,不能提交本地事务。
  •  全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。

以一个示例来说明:

两个全局事务 tx1 tx2,分别对 a 表的 m 字段进行更新操作,m 的初始值 1000

tx1 先开始,开启本地事务,拿到本地锁,更新操作 m = 1000 - 100 = 900。本地事务提交前,先拿到该记录的 全局锁 ,本地提交释放本地锁。 tx2 后开始,开启本地事务,拿到本地锁,更新操作 m = 900 - 100 = 800。本地事务提交前,尝试拿该记录的 全局锁 tx1 全局提交前,该记录的全局锁被 tx1 持有,tx2 需要重试等待 全局锁 

 

tx1 二阶段全局提交,释放 全局锁 tx2 拿到 全局锁 提交本地事务。

 

如果 tx1 的二阶段全局回滚,则 tx1 需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。

此时,如果 tx2 仍在等待该数据的 全局锁,同时持有本地锁,则 tx1 的分支回滚会失败。分支的回滚会一直重试,直到 tx2  全局锁 等锁超时,放弃 全局锁 并回滚本地事务释放本地锁,tx1 的分支回滚最终成功。

因为整个过程 全局锁  tx1 结束前一直是被 tx1 持有的,所以不会发生 脏写 的问题。

读隔离

在数据库本地事务隔离级别 读已提交(Read Committed 或以上的基础上,SeataAT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted 

如果应用在特定场景下,必需要求全局的 读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。

 

SELECT FOR UPDATE 语句的执行会申请 全局锁 ,如果 全局锁 被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到 全局锁 拿到,即读取的相关数据是 已提交 的,才返回。

出于总体性能上的考虑,Seata 目前的方案并没有对所有 SELECT 语句都进行代理,仅针对 FOR UPDATE SELECT 语句。

工作机制

以一个示例来说明整个 AT 分支的工作过程。

业务表:product

Field

Type

Key

id

bigint(20)

PRI

name

varchar(100)

 

since

varchar(100)

 

AT 分支事务的业务逻辑:

update product set name = 'GTS' where name = 'TXC';

一阶段

过程:

  1. 解析 SQL:得到 SQL 的类型(UPDATE),表(product),条件(where name = 'TXC')等相关的信息。
  2. 查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据。
select id, name, since from product where name = 'TXC';

得到前镜像:

id

name

since

1

TXC

2014

  1. 执行业务 SQL:更新这条记录的 name 'GTS'
  2. 查询后镜像:根据前镜像的结果,通过 主键 定位数据。
select id, name, since from product where id = 1;

得到后镜像:

id

name

since

1

GTS

2014

  1. 插入回滚日志:把前后镜像数据以及业务 SQL 相关的信息组成一条回滚日志记录,插入到 UNDO_LOG 表中。
{
         "branchId": 641789253,
         "undoItems": [{
                 "afterImage": {
                          "rows": [{
                                   "fields": [{
                                            "name": "id",
                                            "type": 4,
                                            "value": 1
                                   }, {
                                            "name": "name",
                                            "type": 12,
                                            "value": "GTS"
                                   }, {
                                            "name": "since",
                                            "type": 12,
                                            "value": "2014"
                                   }]
                          }],
                          "tableName": "product"
                 },
                 "beforeImage": {
                          "rows": [{
                                   "fields": [{
                                            "name": "id",
                                            "type": 4,
                                            "value": 1
                                   }, {
                                            "name": "name",
                                            "type": 12,
                                            "value": "TXC"
                                   }, {
                                            "name": "since",
                                            "type": 12,
                                            "value": "2014"
                                   }]
                          }],
                          "tableName": "product"
                 },
                 "sqlType": "UPDATE"
         }],
         "xid": "xid:xxx"
}
  1. 提交前,向 TC 注册分支:申请 product 表中,主键值等于 1 的记录的 全局锁 
  2. 本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。
  3. 将本地事务提交的结果上报给 TC

二阶段-回滚

  1. 收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。
  2. 通过 XID Branch ID 查找到相应的 UNDO LOG 记录。
  3. 数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理。
  4. 根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:
update product set name = 'TXC' where id = 1;
  1. 提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC

二阶段-提交

  1. 收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC
  2. 异步任务阶段的分支提交请求将异步和批量地删除相应 UNDO LOG 记录。

业务代码无侵入。

保证事务隔离性。

DB模式支持高可用

全局锁在高并发情况下可能有一定的性能问题

二、Seata AT接入步骤

用例描述

以user服务和mot服务为例,用户在平台提交删除空间的请求,admin-web作为事务发起方,同时调用user服务删除空间接口和mot服务删除mot策略器接口。

假设此处需要保证一致性,既要么同时失败,要么同时成功,那么此时接口的事务操作需要交给seata来处理。

下面来简单快速的讲一下如何接入seata来管理分布式事务。

框架组件

1. Springboot2.x

2. seata1.4

3. nacos:配置中心

4. zookeeper: 注册中心

5. dubbo2.x

配置Seata服务端

1. 下载seata-server插件

下载地址:https://github.com/seata/seata/releases/

解压后如下图

2. 配置config.txt

config.txt文件需要去github手动下载后放到seata根目录下,和config、bin等文件夹同级

https://github.com/seata/seata/blob/develop/script/config-center/config.txt

 

下载完毕后需要修改如下几项配置

store.mode=db #db模式高可用

 

#数据库配置

store.db.datasource=druid

store.db.db-type=mysql

store.db.driver-class-name=com.mysql.cj.jdbc.Driver

store.db.url=jdbc:mysql://ip:3306/seata

store.db.user=用户名

store.db.password=密码

 

#事务组配置,新增或修改

service.vgroupMapping.user-service-group=default

service.vgroupMapping.mot-service-group=default

service.vgroupMapping.admin-service-group=default

#seata-server服务ip端口

service.default.grouplist=127.0.0.1:8091#seata-server服务的ip端口

 

db模式下的所需的三个表的数据库脚本位于

https://github.com/seata/seata/blob/develop/script/server/db/mysql.sql

 

注意: 配置文件末尾有空行,需要删除,否则会提示失败,尽管实际上是成功的

 

3. 新建logs文件

在seata根目录新建文件夹logs,并在新建的logs文件夹中新建seata_gc.log文件,不然启动seata-server会报错。

 

最终目录结构如下

4. 修改conf/ registry.conf配置

registry {

  #注册中心

  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa

  type = "zk"

  loadBalance = "RandomLoadBalance"

  loadBalanceVirtualNodes = 10

 

  zk {

    cluster = "default"

    serverAddr = "10.11.1.62:2181"

    sessionTimeout = 6000

    connectTimeout = 2000

  }

}

 

config {

  #配置中心

  # file、nacos 、apollo、zk、consul、etcd3

  type = "nacos"

 

  nacos {

    #此处不要加http(s),不然会启动失败,非域名可以直接写IP端口xxx.xx.xx.x:8848

         serverAddr = "nacos.com"

    namespace = "" #此处不填写,会自动写入到public空间下

    group = "SEATA_GROUP"

    username = "用户名"

    password = "密码"

  }

}

 

5. 修改conf/ nacos-config.sh文件

文件需要自行去GitHub下载,因为我这里配置中心用的是nacos所以下载的nacos目录下的shell脚本,其他的请自行选择。

https://github.com/seata/seata/blob/develop/script/config-center/nacos/nacos-config.sh

 

此处要注意,下载文件并放入conf目录后,需要进去修改nacos配置写入的接口地址

因为这里默认认为你的nacos是在本地。

非域名地址也可以在启动sh脚本是使用 -h -p参数手动设置变量

更改后

6. 执行conf/ nacos-config.sh脚本

执行脚本的目的是将config.txt中的配置写入到nacos中,后续seata-server启动需要去nacos读取配置

 

Windows下执行

 

在conf/文件中,利用git客户端的Git Bash Here插件开启面板,使用./ nacos-config.sh执行即可。

成功后

 

Linux下执行

直接执行./ nacos-config.sh 命令即可

 

NACOS效果

 

7. 启动seata-server服务

Windows

进入bin/目录,双击seata-server.bat文件即可。

Linux

进入bin/目录,执行./seata-server.sh 命令即可。

下面窗口,表示启动成功

 

到此seata服务端就处理完毕了,接下来开始处理客户端,即我们的项目工程!!!!

 

 

配置Seata客户端

Seata 客户端就是我们的项目工程,我这里三个服务都是已经架构成熟的,基于

springboot2.x+dubbo2.x+mybatis-plus+nacos(配置)+zk(注册)框架的服务。所以一些基础的搭建

过程我就不再赘述,只会讲一些关于seata的增量的东西。

如果是从0开始的项目,可以先了解如何搭建一套上述架构的系统,再来按照本文接入SEATA。

服务介绍

mot:会员营销服务

user-control:空间管理服务

admin-web: API服务

业务架构

 

分布式事务管理

mot服务

新建undo_log表

每个dubbo服务对应的数据库都需要新建这张表,admin-web不用,因为他没有直接操作数据库。

建表脚本:

https://github.com/seata/seata/blob/develop/script/client/at/db/mysql.sql

 

-- 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';

 

提供dubbo服务

写一个简单的新增标签接口供admin-web调用

 

IMotLabelSerivce.java

public int addLabel(LabelDTO labelDto);

 

MotLabelSerivceImpl.java

@Override

public int addLabel(LabelDTO labelDto){

   motLabelMapper.insert(labelDto);

}

 

配置POM.XML文件

1. 使用seata-spring-boot-starter自动装配数据库代理

<dependency>

         <groupId>io.seata</groupId>

         <artifactId>seata-spring-boot-starter</artifactId>

         <vsersion>1.4.0</version>

</dependency>

 

2. 引入zkclient

这一步看你工程具体架构设计,我这里需要加这个包,注意一点,引入这个包需要排除slf4j-log4j12,不然会冲突。

<dependency>

         <groupId>com.101tec</groupId>

         <artifactId>zkclient</artifactId>

         <version>0.10</version>

         <exclusions>

                   <exclusion>

                            <artifactId>slf4j-log4j12</artifactId>

                   </exclusion>

         </exclusions>

</dependency>

Seata基础配置

这里有两种方案,一是直接在applicaton.yml中写入,另外是在nacos配置中心,新增一个配置文件,我这里选的第二种

 

第一种:直接写入本地application.yml中

seata:

  enabled: true

  application-id: mot

  tx-service-group: mot-service-group #事务群组(对应conf/config.txt中配置service.vgroupMapping.mot-service-group=defaulf的后半部分名称)

  client:

    rm:

      lock:

        retry-interval: 10

        retry-times: 30

        retry-policy-branch-rollback-on-conflict: true

      report-retry-count: 5

      async-commit-buffer-limit: 10000 # 异步提交缓存队列长度(默认10000)

      table-meta-check-enable: false

      report-success-enable: true

    tm:

      commit-retry-count:   3 # 一阶段全局提交结果上报TC重试次数(默认1次,建议大于1)

      rollback-retry-count: 3 # 一阶段全局回滚结果上报TC重试次数(默认1次,建议大于1)

    undo:

      log-table: undo_log # 自定义undo表名(默认undo_log)

      data-validation: true # 二阶段回滚镜像校验(默认true开启)

      log-serialization: jackson # undo序列化方式(默认jackson)

      only-care-update-columns: true

    log:

      exceptionRate: 100 # 日志异常输出概率(默认100)

  enable-auto-data-source-proxy: true#seata开启数据库代理

  service:

    vgroup-mapping: {name: default} # TC 集群(必须与seata-server保持一致)

    enable-degrade: false # 降级开关

    disable-global-transaction: false # 禁用全局事务(默认false)

    grouplist: {ip: 127.0.0.1,port: 8091} #seata-server服务的IP端口

  transport:

    shutdown:

      wait: 3

    thread-factory:

      boss-thread-prefix: NettyBoss

      worker-thread-prefix: NettyServerNIOWorker

      server-executor-thread-prefix: NettyServerBizHandler

      share-boss-worker: false

      client-selector-thread-prefix: NettyClientSelector

      client-selector-thread-size: 1

      client-worker-thread-prefix: NettyClientWorkerThread

    type: TCP

    server: NIO

    heartbeat: true

    serialization: seata

    compressor: none

    enable-client-batch-send-request: true # 客户端事务消息请求是否批量合并发送(默认true)

  registry:

    type: zk

    zk:

      cluster: default

      server-addr: 10.11.1.62:2181

      session-timeout: 6000

  config:

    type: nacos

    nacos:

      namespace:

      server-addr: https://nacos-test.01member.com #这里的地址如果是https的需要写死在这里,不然获取配置时,会自动使用http协议

      password: axGgTRUopxXbXTMATbU4E29o

      username: nacos

      group: SEATA_GROUP

 

 

第二种:使用nacos配置中心

Step1 在私有空间中新增配置文件

dataId: seata.yml

group: mot

输入文件内容,点击发布即可

seata:

  enabled: true

  application-id: mot

  tx-service-group: mot-service-group # 事务群组(可以每个应用独立取名,也可以使用相同的名字)

  client:

    rm:

      lock:

        retry-interval: 10

        retry-times: 30

        retry-policy-branch-rollback-on-conflict: true

      report-retry-count: 5

      async-commit-buffer-limit: 10000 # 异步提交缓存队列长度(默认10000)

      table-meta-check-enable: false

      report-success-enable: true

    tm:

      commit-retry-count:   3 # 一阶段全局提交结果上报TC重试次数(默认1次,建议大于1)

      rollback-retry-count: 3 # 一阶段全局回滚结果上报TC重试次数(默认1次,建议大于1)

    undo:

      log-table: undo_log # 自定义undo表名(默认undo_log)

      data-validation: true # 二阶段回滚镜像校验(默认true开启)

      log-serialization: jackson # undo序列化方式(默认jackson)

      only-care-update-columns: true

    log:

      exceptionRate: 100 # 日志异常输出概率(默认100)

  enable-auto-data-source-proxy: true #seata接管数据库代理

  service:

    vgroup-mapping: {name: default} # TC 集群(必须与seata-server保持一致)

    enable-degrade: false # 降级开关

    disable-global-transaction: false # 禁用全局事务(默认false)

    grouplist: {ip: 127.0.0.1,port: 8091}

  transport:

    shutdown:

      wait: 3

    thread-factory:

      boss-thread-prefix: NettyBoss

      worker-thread-prefix: NettyServerNIOWorker

      server-executor-thread-prefix: NettyServerBizHandler

      share-boss-worker: false

      client-selector-thread-prefix: NettyClientSelector

      client-selector-thread-size: 1

      client-worker-thread-prefix: NettyClientWorkerThread

    type: TCP

    server: NIO

    heartbeat: true

    serialization: seata

    compressor: none

    enable-client-batch-send-request: true # 客户端事务消息请求是否批量合并发送(默认true)

  registry:

    type: zk

    zk:

      cluster: default

      server-addr: 10.11.1.62:2181

      session-timeout: 6000

  config:

    type: nacos

    nacos:

      namespace:

      server-addr: https://nacos-test.01member.com

      password: axGgTRUopxXbXTMATbU4E29o

      username: nacos

      group: SEATA_GROUP

Step2 在applicationContext-nacos.xml文件中配置seata.yml

<!-- seata分布式事务配置 -->

<nacos:property-source data-id="seata.yml" group-id="${spring.application.name}" auto-refreshed="true"/>

 

启动MOT服务

执行ScrmMotApplication.java的main方法后,查看seata-server服务窗口,成功后如下图

(使用鼠标滚轮扩大后更清晰)

 

user-control服务

新建undo_log表

每个dubbo服务对应的数据库都需要新建这张表,admin-web不用,因为他没有直接操作数据库。

建表脚本:

https://github.com/seata/seata/blob/develop/script/client/at/db/mysql.sql

 

-- 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';

 

提供dubbo服务

写一个简单的新增空间的接口供admin-web调用

 

IUserSpaceService.java

public int addSpace(SpaceDTO spaceDto);

 

UserSpaceSerivceImpl.java

@Override

public int addSpace(SpaceDTO spaceDto){

   userSpaceMapper.insert(spaceDto);

}

 

配置POM.XML文件

1. 使用seata-spring-boot-starter自动装配数据库代理

<dependency>

         <groupId>io.seata</groupId>

         <artifactId>seata-spring-boot-starter</artifactId>

         <vsersion>1.4.0</version>

</dependency>

 

2. 引入zkclient

这一步看你工程具体架构设计,我这里需要加这个包,注意一点,引入这个包需要排除slf4j-log4j12,不然会冲突。

<dependency>

         <groupId>com.101tec</groupId>

         <artifactId>zkclient</artifactId>

         <version>0.10</version>

         <exclusions>

                   <exclusion>

                            <artifactId>slf4j-log4j12</artifactId>

                   </exclusion>

         </exclusions>

</dependency>

Seata基础配置

这里有两种方案,一是直接在applicaton.yml中写入,另外是在nacos配置中心,新增一个配置文件,我这里选的第二种

 

第一种:直接写入本地application.yml中

seata:

  enabled: true

  application-id: user-control

  tx-service-group: user-service-group #事务群组(对应conf/config.txt中配置service.vgroupMapping.user-service-group=defaulf的后半部分名称)

  client:

    rm:

      lock:

        retry-interval: 10

        retry-times: 30

        retry-policy-branch-rollback-on-conflict: true

      report-retry-count: 5

      async-commit-buffer-limit: 10000 # 异步提交缓存队列长度(默认10000)

      table-meta-check-enable: false

      report-success-enable: true

    tm:

      commit-retry-count:   3 # 一阶段全局提交结果上报TC重试次数(默认1次,建议大于1)

      rollback-retry-count: 3 # 一阶段全局回滚结果上报TC重试次数(默认1次,建议大于1)

    undo:

      log-table: undo_log # 自定义undo表名(默认undo_log)

      data-validation: true # 二阶段回滚镜像校验(默认true开启)

      log-serialization: jackson # undo序列化方式(默认jackson)

      only-care-update-columns: true

    log:

      exceptionRate: 100 # 日志异常输出概率(默认100)

  enable-auto-data-source-proxy: true #seata开启数据库代理

  service:

    vgroup-mapping: {name: default} # TC 集群(必须与seata-server保持一致)

    enable-degrade: false # 降级开关

    disable-global-transaction: false # 禁用全局事务(默认false)

    grouplist: {ip: 127.0.0.1,port: 8091} #seata-server服务的IP端口

 

  transport:

    shutdown:

      wait: 3

    thread-factory:

      boss-thread-prefix: NettyBoss

      worker-thread-prefix: NettyServerNIOWorker

      server-executor-thread-prefix: NettyServerBizHandler

      share-boss-worker: false

      client-selector-thread-prefix: NettyClientSelector

      client-selector-thread-size: 1

      client-worker-thread-prefix: NettyClientWorkerThread

    type: TCP

    server: NIO

    heartbeat: true

    serialization: seata

    compressor: none

    enable-client-batch-send-request: true # 客户端事务消息请求是否批量合并发送(默认true)

  registry:

    type: zk

    zk:

      cluster: default

      server-addr: 10.11.1.62:2181

      session-timeout: 6000

  config:

    type: nacos

    nacos:

      namespace:

      server-addr: https://nacos.com#这里的地址如果是https的需要写死在这里,不然获取配置时,会自动使用http协议

      password: axGgTRUopxXbXTMATbU4E29o

      username: nacos

      group: SEATA_GROUP

 

 

第二种:使用nacos配置中心

Step1 在私有空间中新增配置文件

dataId: seata.yml

group: mot

输入文件内容,点击发布即可

seata:

  enabled: true

  application-id: user-control

  tx-service-group: user-service-group # 事务群组(可以每个应用独立取名,也可以使用相同的名字)

  client:

    rm:

      lock:

        retry-interval: 10

        retry-times: 30

        retry-policy-branch-rollback-on-conflict: true

      report-retry-count: 5

      async-commit-buffer-limit: 10000 # 异步提交缓存队列长度(默认10000)

      table-meta-check-enable: false

      report-success-enable: true

    tm:

      commit-retry-count:   3 # 一阶段全局提交结果上报TC重试次数(默认1次,建议大于1)

      rollback-retry-count: 3 # 一阶段全局回滚结果上报TC重试次数(默认1次,建议大于1)

    undo:

      log-table: undo_log # 自定义undo表名(默认undo_log)

      data-validation: true # 二阶段回滚镜像校验(默认true开启)

      log-serialization: jackson # undo序列化方式(默认jackson)

      only-care-update-columns: true

    log:

      exceptionRate: 100 # 日志异常输出概率(默认100)

  enable-auto-data-source-proxy: true #seata接管数据库代理

  service:

    vgroup-mapping: {name: default} # TC 集群(必须与seata-server保持一致)

    enable-degrade: false # 降级开关

    disable-global-transaction: false # 禁用全局事务(默认false)

    grouplist: {ip: 127.0.0.1,port: 8091}

  transport:

    shutdown:

      wait: 3

    thread-factory:

      boss-thread-prefix: NettyBoss

      worker-thread-prefix: NettyServerNIOWorker

      server-executor-thread-prefix: NettyServerBizHandler

      share-boss-worker: false

      client-selector-thread-prefix: NettyClientSelector

      client-selector-thread-size: 1

      client-worker-thread-prefix: NettyClientWorkerThread

    type: TCP

    server: NIO

    heartbeat: true

    serialization: seata

    compressor: none

    enable-client-batch-send-request: true # 客户端事务消息请求是否批量合并发送(默认true)

  registry:

    type: zk

    zk:

      cluster: default

      server-addr: 10.11.1.62:2181

      session-timeout: 6000

  config:

    type: nacos

    nacos:

      namespace:

      server-addr: https://nacos.com#这里的地址如果是https的需要写死在这里,不然获取配置时,会自动使用http协议

      password: axGgTRUopxXbXTMATbU4E29o

      username: nacos

      group: SEATA_GROUP

Step2 在applicationContext-nacos.xml文件中配置seata.yml

<!-- seata分布式事务配置 -->

<nacos:property-source data-id="seata.yml" group-id="${spring.application.name}" auto-refreshed="true"/>

 

启动user-control服务

执行UserControlApplication.java的main方法后,查看seata-server服务窗口,成功后如下图

(使用鼠标滚轮扩大后更清晰)

admin-web服务

提供web API

写一个简单的web接口

 

MotSeataController.java

@Api(tags = "SEATA")

@RestController

@RequestMapping("/v1/seata")

public class MotSeataController{

        

         @Autowired

         private SeataAddTestService seataAddTestService;

        

         @ApiOperation(value = "seata-test")

         @PostMapping("/add")

         public ResultDTO<Void> add(){

                   try {

                            return seataAddTestService.add();

                   } catch (Exception e) {

                            e.printStackTrace();

                   }

                   return ResultDTO.success();

         }

}

 

写个简单的service

SeataAddTestService.java

public interface SeataAddTestService {

         public ResultDTO<Void> add() throws Exception ;

}

接口实现类

SeataAddTestServiceImpl.java

@Service

@Slf4j

public class SeataAddTestServiceImpl implements SeataAddTestService {

         @Autowired

         private IMotStrategyCrowdService motStrategyCrowdService;

 

         @Autowired

         private RoleService roleService;

         @GlobalTransactional(rollbackFor = Exception.class,timeoutMills = 300000, name = "admin-web")

         @Override

         public ResultDTO<Void> add() throws Exception{

                   log.info("开始全局事务,XID = " + RootContext.getXID());

                   RolePermissionDTO rolePermissionDTO = new RolePermissionDTO();

                   rolePermissionDTO.setDomainId("aaaa-v-b-b-b");

                   List<Integer> permissionIds = new ArrayList<Integer>();

                   permissionIds.add(1);

                   rolePermissionDTO.setPermissionIds(permissionIds);

                   rolePermissionDTO.setRoleName("seata");

                   rolePermissionDTO.setRoleStatus(false);

 

        // 先调用user-control服务的新增接口

                   roleService.addRole(rolePermissionDTO);

                  

                   MotStrategyCrowdDTO motStrategyCrowdDTO = new MotStrategyCrowdDTO();

                   motStrategyCrowdDTO.setCollectTimeNumber(1);

                   motStrategyCrowdDTO.setCollectTimeUnit(1);

                   motStrategyCrowdDTO.setCrowdName("seata");

                   motStrategyCrowdDTO.setCrowdNumber(1);

                   motStrategyCrowdDTO.setCrowdType(1);

                   motStrategyCrowdDTO.setRules("seata");

        // 再调用MOT服务的新增接口

                   motStrategyCrowdService.createCrowd(motStrategyCrowdDTO);

 

        // 然后手动抛出异常

                   throw new Exception();

//               return ResultDTO.success();

         }

}

 

 

配置POM.XML文件

1. 使用seata-spring-boot-starter自动装配数据库代理

<dependency>

         <groupId>io.seata</groupId>

         <artifactId>seata-spring-boot-starter</artifactId>

         <vsersion>1.4.0</version>

</dependency>

 

2. 引入zkclient

这一步看你工程具体架构设计,我这里需要加这个包,注意一点,引入这个包需要排除slf4j-log4j12,不然会冲突。

<dependency>

         <groupId>com.101tec</groupId>

         <artifactId>zkclient</artifactId>

         <version>0.10</version>

         <exclusions>

                   <exclusion>

                            <artifactId>slf4j-log4j12</artifactId>

                   </exclusion>

         </exclusions>

</dependency>

 

3. spring-boot-starter-web也需要排除org.slf4j

<dependency>

          <groupId>org.springframework.boot</groupId>

          <artifactId>spring-boot-starter-web</artifactId>

          <exclusions>

                     <exclusion>

                               <groupId>org.slf4j</groupId>

                               <artifactId>slf4j-log4j12</artifactId>

                     </exclusion>

          </exclusions>

</dependency>

Seata基础配置

这里有两种方案,一是直接在applicaton.yml中写入,另外是在nacos配置中心,新增一个配置文件,我这里选的第二种

在admin-web中,有些配置时无用的,可以去掉,具体的自己研究。写在这里也不会有问题。

第一种:直接写入本地application.yml中

 

seata:

  enabled: true

  application-id: admin-web

  tx-service-group: admin-service-group #事务群组(对应conf/config.txt中配置service.vgroupMapping.admin-service-group=defaulf的后半部分名称)

  client:

    rm:

      lock:

        retry-interval: 10

        retry-times: 30

        retry-policy-branch-rollback-on-conflict: true

      report-retry-count: 5

      async-commit-buffer-limit: 10000 # 异步提交缓存队列长度(默认10000)

      table-meta-check-enable: false

      report-success-enable: true

    tm:

      commit-retry-count:   3 # 一阶段全局提交结果上报TC重试次数(默认1次,建议大于1)

      rollback-retry-count: 3 # 一阶段全局回滚结果上报TC重试次数(默认1次,建议大于1)

    undo:

      log-table: undo_log # 自定义undo表名(默认undo_log)

      data-validation: true # 二阶段回滚镜像校验(默认true开启)

      log-serialization: jackson # undo序列化方式(默认jackson)

      only-care-update-columns: true

    log:

      exceptionRate: 100 # 日志异常输出概率(默认100)

  enable-auto-data-source-proxy: true #seata开启数据库代理

  service:

    vgroup-mapping: {name: default} # TC 集群(必须与seata-server保持一致)

    enable-degrade: false # 降级开关

    disable-global-transaction: false # 禁用全局事务(默认false)

    grouplist: {ip: 127.0.0.1,port: 8091} #seata-server服务的IP端口

 

  transport:

    shutdown:

      wait: 3

    thread-factory:

      boss-thread-prefix: NettyBoss

      worker-thread-prefix: NettyServerNIOWorker

      server-executor-thread-prefix: NettyServerBizHandler

      share-boss-worker: false

      client-selector-thread-prefix: NettyClientSelector

      client-selector-thread-size: 1

      client-worker-thread-prefix: NettyClientWorkerThread

    type: TCP

    server: NIO

    heartbeat: true

    serialization: seata

    compressor: none

    enable-client-batch-send-request: true # 客户端事务消息请求是否批量合并发送(默认true)

  registry:

    type: zk

    zk:

      cluster: default

      server-addr: 10.11.1.62:2181

      session-timeout: 6000

  config:

    type: nacos

    nacos:

      namespace:

      server-addr: https://nacos.com#这里的地址如果是https的需要写死在这里,不然获取配置时,会自动使用http协议

      password: axGgTRUopxXbXTMATbU4E29o

      username: nacos

      group: SEATA_GROUP

 

 

第二种:使用nacos配置中心

Step1 在私有空间中新增配置文件

dataId: seata.yml

group: mot

输入文件内容,点击发布即可

seata:

  enabled: true

  application-id: admin-web

  tx-service-group: admin-service-group # 事务群组(可以每个应用独立取名,也可以使用相同的名字)

  client:

    rm:

      lock:

        retry-interval: 10

        retry-times: 30

        retry-policy-branch-rollback-on-conflict: true

      report-retry-count: 5

      async-commit-buffer-limit: 10000 # 异步提交缓存队列长度(默认10000)

      table-meta-check-enable: false

      report-success-enable: true

    tm:

      commit-retry-count:   3 # 一阶段全局提交结果上报TC重试次数(默认1次,建议大于1)

      rollback-retry-count: 3 # 一阶段全局回滚结果上报TC重试次数(默认1次,建议大于1)

    undo:

      log-table: undo_log # 自定义undo表名(默认undo_log)

      data-validation: true # 二阶段回滚镜像校验(默认true开启)

      log-serialization: jackson # undo序列化方式(默认jackson)

      only-care-update-columns: true

    log:

      exceptionRate: 100 # 日志异常输出概率(默认100)

  enable-auto-data-source-proxy: true #seata接管数据库代理

  service:

    vgroup-mapping: {name: default} # TC 集群(必须与seata-server保持一致)

    enable-degrade: false # 降级开关

    disable-global-transaction: false # 禁用全局事务(默认false)

    grouplist: {ip: 127.0.0.1,port: 8091}

  transport:

    shutdown:

      wait: 3

    thread-factory:

      boss-thread-prefix: NettyBoss

      worker-thread-prefix: NettyServerNIOWorker

      server-executor-thread-prefix: NettyServerBizHandler

      share-boss-worker: false

      client-selector-thread-prefix: NettyClientSelector

      client-selector-thread-size: 1

      client-worker-thread-prefix: NettyClientWorkerThread

    type: TCP

    server: NIO

    heartbeat: true

    serialization: seata

    compressor: none

    enable-client-batch-send-request: true # 客户端事务消息请求是否批量合并发送(默认true)

  registry:

    type: zk

    zk:

      cluster: default

      server-addr: 10.11.1.62:2181

      session-timeout: 6000

  config:

    type: nacos

    nacos:

      namespace:

      server-addr: https://nacos.com#这里的地址如果是https的需要写死在这里,不然获取配置时,会自动使用http协议

      password: axGgTRUopxXbXTMATbU4E29o

      username: nacos

      group: SEATA_GROUP

Step2 在applicationContext-nacos.xml文件中配置seata.yml

<!-- seata分布式事务配置 -->

<nacos:property-source data-id="seata.yml" group-id="${spring.application.name}" auto-refreshed="true"/>

 

启动admin-web服务

执行ScrmAdminApplication.java的main方法后,开始访问接口

http://localhost:8181/v1/seata/add

查看seata-server窗口,末尾会有几行事务回滚的过程日志。可以结合目录:服务介绍/分布式事务管理的图分析日志。

# 回滚第一个分支事务

Rollback branch transaction successfully, xid = 10.11.1.62:8091:72384271135006720 branchId = 72384292370767872

# 回滚第二个分支事务

Rollback branch transaction successfully, xid = 10.11.1.62:8091:72384271135006720 branchId = 72384279662026752

# 全局事务回滚 真正的回滚

Rollback global transaction successfully, xid = 10.11.1.62:8091:72384271135006720.

 

查看数据库,发现数据确实新增失败了,这里回滚是因为我们在admin-web的方法中手动抛出了异常,被seata的注解捕获从而进行回滚

@GlobalTransactional(rollbackFor = Exception.class,timeoutMills = 300000, name = "admin-web")

 

为了进一步验证事务是否生效,这里将异常注释掉,再重新启动服务和调用接口

 

查看SeaTa-server窗口日志,显示服务提交成功

 

查看数据库 数据也新增成功了,到这里基本就KO了。

 

三、注意事项

1. 所有使用分布式事务的表必须且只有一个主键。

2. spring.application.name、dubbo.application.name、seata.application-id这三个名称必须一致。

3. 如果按照上述文档无法实现分布式事务的正常提交回滚,请联系我或者自行百度!!!

4. 百度时候要区分seata版本1.0前后有比较大的区别。

5. 百度的时候要区分dubbo和springcloud的接入方式,还是有区别的。

6. 官方文档:https://seata.io/zh-cn/docs/user/quickstart.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值