springcloudalibabaseata分布式事务解决方案(代码片段)

AC_Jobim AC_Jobim     2022-12-11     746

关键词:

Spring Cloud Alibaba Seata 分布式事务解决方案

一、分布式事务问题

  • 一次业务操作需要跨多个数据源或者需要跨多个系统进行远程调用,就会产生分布式事务问题。

举例:

用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:

  • 仓储服务:对给定的商品扣除仓储数量。
  • 订单服务:根据采购需求创建订单。
  • 帐户服务:从用户帐户中扣除余额。

单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源,业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证,但是全局数据一致性问题是无法保证的。

二、Seata简介

Seata官网地址:http://seata.io/zh-cn/

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

Seata术语:

  • TC (Transaction Coordinator) - 事务协调者
    维护全局和分支事务的状态,驱动全局事务提交或回滚。

  • TM (Transaction Manager) - 事务管理器
    定义全局事务的范围:开始全局事务、提交或回滚全局事务。

  • RM (Resource Manager) - 资源管理器
    管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

Seata处理过程:

  1. TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID;
  2. XID在微服务调用链路的上下文传播;
  3. RM向TC注册分支事务,将其纳入XID对应全局事务的管辖;
  4. TM向TC发起针对XID的全局提交或回滚决议;
  5. TC调度XID下管辖的全部分支事务完成提交或者回滚请求

三、Seata的部署

Seata的版本选择: Spring Cloud Alibaba与Spring Boot、Spring Cloud版本对应关系

官网版本说明

本次使用:Seata 1.2.0

3.1 Seata Server端配置

官方配置文档:Seata部署指南

下载seata-server-1.2.0和seata-1.2.0源码

  • seate-server下载: https://seata.io/zh-cn/blog/download.html
  • seata-1.2.0源码下载: https://github.com/seata/seata/releases

3.1.1 修改配置文件

解压后,进入 conf 目录开始参数的配置。我们修改 file.confregistry.conf 这两个文件。

1、进入conf文件夹,修改file.conf文件

2、修改registry.conf文件

  • 如果config设置成了file,则不需要网上的设置nacos的配置

3.1.2 MySQL 数据库配置

我们先创建数据库seata(数据库要与file.conf中db设置那里对应),数据库的建表语句在README文件的server连接中

让后执行mysql.sql

-- -------------------------------- 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(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

-- 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 = utf8;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(96),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

3.1.3 启动Seata Server端

3.2 Seata Client 客户端配置

3.2.1 业务前置准备

业务场景:用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:

用户A购买商品,调用 A服务 创建订单完成,调用 B服务 扣减库存,然后调用 C服务 扣减账户余额。每个服务内部的数据一致性由本地事务来保证,多个服务调用来完成业务,全局事务数据一致性则由 Seata 来保证。

  • 订单服务A:根据采购需求创建订单。

  • 仓储服务B:对给定的商品扣除仓储数量。

  • 帐户服务C:从用户帐户中扣除余额。

**业务数据库准备:**配置三个业务分别对应各自的数据库。

  • A服务 对应数据库:seata_order ;表:t_order
  • B服务 对应数据库:seata_storage ;表:t_storage
  • C服务 对应数据库:seata_account ;表:t_account

建表语句:

# 创建seata_order数据库
CREATE DATABASE seata_order;

# 创建t_order表
CREATE TABLE seata_order.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 '订单状态:0:创建中; 1:已完结'
) ENGINE=INNODB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
# 创建seata_storage数据库
CREATE DATABASE seata_storage;

# 创建t_storage表
CREATE TABLE seata_storage.t_storage(
    `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',
    `total` INT(11) DEFAULT NULL COMMENT '总库存',
    `used` INT(11) DEFAULT NULL COMMENT '已用库存',
    `residue` INT(11) DEFAULT NULL COMMENT '剩余库存'
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

# 插入一条数据 
INSERT INTO seata_storage.t_storage(`id`,`product_id`,`total`,`used`,`residue`)
VALUES('1','1','100','0','100');
# 创建seata_account数据库
CREATE DATABASE seata_account;

# 创建t_account表
CREATE TABLE seata_account.t_account(
    `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'id',
    `user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',
    `total` DECIMAL(10,0) DEFAULT NULL COMMENT '总额度',
    `used` DECIMAL(10,0) DEFAULT NULL COMMENT '已用余额',
    `residue` DECIMAL(10,0) DEFAULT '0' COMMENT '剩余可用额度'
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

# 插入一条数据 
INSERT INTO seata_account.t_account(`id`,`user_id`,`total`,`used`,`residue`) VALUES('1','1','1000','0','1000');

3.2.2 创建undo_log表

按照上述3库分别建对应的回滚日志表,建表文件在README_ZH文件中的client中

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`
(
    `id`            BIGINT(20)   NOT NULL AUTO_INCREMENT COMMENT 'increment id',
    `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     NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME     NOT NULL COMMENT 'modify datetime',
    PRIMARY KEY (`id`),
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

完成图示:

以下配置以seata-order-service2001为例

  • 项目结构:

3.2.3 Seata Client配置文件

配置文件的编写参考README_ZH文件中的client中:

1、file.conf,修改这一处

transport 
  # tcp, unix-domain-socket
  type = "TCP"
  #NIO, NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  # the tm client batch send request enable
  enableTmClientBatchSendRequest = false
  # the rm client batch send request enable
  enableRmClientBatchSendRequest = true
   # the rm client rpc request timeout
  rpcRmRequestTimeout = 2000
  # the tm client rpc request timeout
  rpcTmRequestTimeout = 10000
  # the tc client rpc request timeout
  rpcTcRequestTimeout = 5000
  #thread factory for netty
  threadFactory 
    bossThreadPrefix = "NettyBoss"
    workerThreadPrefix = "NettyServerNIOWorker"
    serverExecutorThread-prefix = "NettyServerBizHandler"
    shareBossWorker = false
    clientSelectorThreadPrefix = "NettyClientSelector"
    clientSelectorThreadSize = 1
    clientWorkerThreadPrefix = "NettyClientWorkerThread"
    # netty boss thread size
    bossThreadSize = 1
    #auto default pin or 8
    workerThreadSize = "default"
  
  shutdown 
    # when destroy server, wait seconds
    wait = 3
  
  serialization = "seata"
  compressor = "none"

service 
  #transaction service group mapping
  vgroupMapping.my_test_tx_group = "default"
  #only support when registry.type=file, please don't set multiple addresses
  default.grouplist = "127.0.0.1:8091"
  #degrade, current not support
  enableDegrade = false
  #disable seata
  disableGlobalTransaction = false


client 
  rm 
    asyncCommitBufferLimit = 10000
    lock 
      retryInterval = 10
      retryTimes = 30
      retryPolicyBranchRollbackOnConflict = true
    
    reportRetryCount = 5
    tableMetaCheckEnable = false
    tableMetaCheckerInterval = 60000
    reportSuccessEnable = false
    sagaBranchRegisterEnable = false
    sagaJsonParser = "fastjson"
    sagaRetryPersistModeUpdate = false
    sagaCompensatePersistModeUpdate = false
    tccActionInterceptorOrder = -2147482648 #Ordered.HIGHEST_PRECEDENCE + 1000
  
  tm 
    commitRetryCount = 5
    rollbackRetryCount = 5
    defaultGlobalTransactionTimeout = 60000
    degradeCheck = false
    degradeCheckPeriod = 2000
    degradeCheckAllowTimes = 10
    interceptorOrder = -2147482648 #Ordered.HIGHEST_PRECEDENCE + 1000
  
  undo 
    dataValidation = true
    onlyCareUpdateColumns = true
    logSerialization = "jackson"
    logTable = "undo_log"
    compress 
      enable = true
      # allow zip, gzip, deflater, 7z, lz4, bzip2, zstd default is zip
      type = zip
      # if rollback info size > threshold, then will be compress
      # allow k m g t
      threshold = 64k
    
  
  loadBalance 
      type = "RandomLoadBalance"
      virtualNodes = 10
  

log 
  exceptionRate = 100

tcc 
  fence 
    # tcc fence log table name
    logTableName = tcc_fence_log
    # tcc fence log clean period
    cleanPeriod = 1h
  

2、registry.conf,修改这一处

registry 
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa、custom
  type = "nacos"

  nacos 
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    namespace = ""
    username = ""
    password = ""
    ##if use MSE Nacos with auth, mutex with username/password attribute
    #accessKey = ""
    #secretKey = ""
  
  eureka 
    serviceUrl = "http://localhost:8761/eureka"
    weight = "1"
  
  redis 
    serverAddr = "localhost:6379"
    db = "0"
    password = ""
    timeout = "0"
  
  zk 
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
  
  consul 
    serverAddr = "127.0.0.1:8500"
    aclToken = ""
  
  etcd3 
    serverAddr = "http://localhost:2379"
  
  sofa 
    serverAddr = "127.0.0.1:9603"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  
  file 
    name = "file.conf"
  
  custom 
    name = ""
  


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

  nacos 
    serverAddr = "127.0.0.1:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = ""
    password = ""
    ##if use MSE Nacos with auth, mutex with username/password attribute
    #accessKey = ""
    #secretKey = ""
    dataId = "seata.properties"
  
  consul 
    serverAddr = "127.0.0.1:8500"
	key = "seata.properties"
    aclToken = ""
  
  apollo 
    appId = "seata-server"
    apolloMeta = "http://192.168.1.204:8801"
    namespace = "application"
    apolloAccesskeySecret = ""
  
  zk 
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
    nodePath = "/seata/seata.properties"
  
  etcd3 
    serverAddr = "http://localhost:2379"
    key = "seata.properties"
  
  file 
    name = "file.conf"
  
  custom 
    name = ""
  

3.2.4 pom.xml文件

<dependencies>
    <!--nacos-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--seata-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        <exclusions>
            <exclusion>
                <artifactId>seata-all</artifactId>
                <groupId>io.seata</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>io.seata</groupId>
        <artifactId>seata-all</artifactId>
        <version>1.2.0</version>
    </dependency>
    <!--feign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!--web-actuator-->
    <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>
    <!--mysql-druid-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.37</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupI

springcloudalibabaseata处理分布式事务及示例demo(代码片段)

创建undo_log表,此表为seata框架使用:CREATETABLE`undo_log`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`branch_id`bigint(20)NOTNULL,`xid`varchar(100)NOTNULL,`context` 查看详情

springcloudalibabaseata分布式事务使用快速入门,nacos做seata的注册中心和配置中心

SpringCloudSeata分布式事务使用快速入门特点1、文档教程详细且提供完整源码及数据库脚本2、有配套全手敲代码的视频演示教程使用版本SpringCloudAlibaba2021.1Nacos1.4.1Seata1.3.0概念说明:本地事务及分布式事务本地事务1、在一个进... 查看详情

springcloudalibabaseata分布式事务使用快速入门,nacos做seata的注册中心和配置中心(代码片段)

SpringCloudSeata分布式事务使用快速入门特点1、文档教程详细且提供完整源码及数据库脚本2、有配套全手敲代码的视频演示教程使用版本SpringCloudAlibaba2021.1Nacos1.4.1Seata1.3.0概念说明:本地事务及分布式事务本地事务1、在一个进... 查看详情

springcloudalibabaseata分布式事务解决方案(代码片段)

SpringCloudAlibabaSeata分布式事务解决方案一、分布式事务问题二、Seata简介三、Seata的部署3.1SeataServer端配置3.1.1修改配置文件3.1.2MySQL数据库配置3.1.3启动SeataServer端3.2SeataClient客户端配置3.2.1业务前置准备3.2.2创建undo_log表3.2.3SeataClient... 查看详情

springcloudalibabaseata分布式事务(代码片段)

超详细的Java知识点路线图Seata简介在传统的单体项目中,我们使用@Transactional注解就能实现基本的ACID事务了。但是前提是:1)数据库支持事务(如:MySQL的innoDB引擎)2)所有业务都在同一个数据库... 查看详情

springcloudalibabaseata分布式事务使用快速入门,nacos做seata的注册中心和配置中心(代码片段)

SpringCloudSeata分布式事务使用快速入门特点1、文档教程详细且提供完整源码及数据库脚本2、有配套全手敲代码的视频演示教程使用版本SpringCloudAlibaba2021.1Nacos1.4.1Seata1.3.0概念说明:本地事务及分布式事务本地事务1、在一个进... 查看详情

springcloudalibabaseata集成(代码片段)

主项目链接:https://gitee.com/java_wxid/java_wxid项目架构及博文总结:点击:【使用SpringBoot快速构建应用】点击:【使用SpringCloudOpenFeign基于动态代理动态构造请求实现与其他系统进行交互】点击:【使用SpringCloudHy... 查看详情

seata:分布式事务(代码片段)

SpringCloudAlibabaSeata:分布式事务一、Seata简介1.Seata的由来​随着互联网项目的发展,分布式架构的项目显示出了独特的独特的魅力。但是分布式事务问题在分布式架构项目中越显重要。​2019年1月阿里巴巴团队发起了开源项目Fesca... 查看详情

springcloudalibabaseata集成(代码片段)

文章目录SeataServer部署:DB存储模式+Nacos(注册&配置中心)部署步骤一:下载安装包步骤二:建表(仅db模式)步骤三:修改store.mode步骤四:修改数据库连接步骤五:配置Nacos步骤六:启动SeataServerSeataCl... 查看详情

springcloud微服务架构(基础详解)(代码片段)

...acos集群与持久化SpringCloudAlibabaSentinel服务熔断降级、限流SpringCloudAlibabaSeata分布式事务框架微服务架构的概念微服务架构是一种架构模式,它提倡将单一的应用程序划分成一组小的服务,服务之间互相协 查看详情

4.抽样分布—卡方分布f分布t分布beta分布gamma分布——python实战

...统计量常用统计量次度统计量充分统计量2、什么是抽样分布3、卡方分布概率密度python代码实现性质非中心卡方分布4、t分布概率密度python代码实现性质5、F分布概率密度python代码实现性质6、样本分布7、其他类型分布Gamma分布族Be... 查看详情

常用的概率分布:二项式分布,贝塔分布,狄里克雷分布

知识点:伯努利分布、二项式分布、多项式分布、先验概率,后验概率,共轭分布、贝塔分布、贝塔-二项分布、负二项分布、狄里克雷分布,伽马函数、分布一,伯努利分布(bernoulidistribution)又叫做0-1分布,指一次随机试验,结... 查看详情

分布式(分布式事务/分布式协议/分布式id/分布式锁)

分布式事务/分布式协议一文说清各种分布式一致性协议_wh柒八九的博客-CSDN博客_分布式一致性协议分布式ID 美团(Leaf)分布式ID算法_wh柒八九的博客-CSDN博客_美团leaf算法 脑裂问题解决办法高可用集群的脑裂问题_wh柒八... 查看详情

抽样分布t分布

定义t分布设X~N(0,1),Y~ χ2(n),且X,Y相互独立,则称随机变量          服从自由度为n的t分布(学生氏分布)记为t~t(n),其概率密度为由于tn(x)是偶函数,其图形关于y轴对称。当n趋于无穷大时,t分布以标准正态... 查看详情

(0,1)分布(两点分布)

定义两点分布的期望和方差期望[EX=p]方差[DX=p(1-p)]注:证明见二项分布. 查看详情

正态分布与偏态分布的概念

正态分布又称高斯分布,是一种最重要的连续型分布。它是以均数为中心呈对称的钟型分布。早在1733年a.demoivre首先提出这种分布的方程,他以此作为二项分布的极限形式。至19世纪初期,德国数学家c.f.gauss与法国数学家p.s.delapla... 查看详情

伯努利分布二项分布多项分布beta分布dirichlet分布

1.伯努利分布伯努利分布(Bernoullidistribution)又名两点分布或0-1分布,介绍伯努利分布前首先需要引入伯努利试验(Bernoullitrial)。伯努利试验是只有两种可能结果的单次随机试验,即对于一个随机变量X而言: 伯努利试验都可... 查看详情

二项分布,多项分布,以及与之对应的beta分布和狄利克雷分布

1.二项分布与beta分布对应  2.多项分布与狄利克雷分布对应3.二项分布是什么?n次bernuli试验服从二项分布  二项分布是N次重复bernuli试验结果的分布。bernuli实验是什么?做一次抛硬币实验,该试验结果只有2种情况,x=1,... 查看详情