SpringCloud 整合分布式事务组件 Seata (八)

简介: SpringCloud 整合分布式事务组件 Seata (八)

正文



什么都不说,我们按照惯例,先上一个图(图里不规范的使用请忽略):


image.png简单一眼就看出来, 比我们平时用的东西,多了  Seata Server 微服务 。


同样这个 Seata Server 微服务  ,也是需要注册到eureka上面去的。


那么我们首先就搞一搞这个 seata server ,那么剩下的就是一些原本的业务服务整合配置了。


该篇用的 seata server 版本,用的是1.4.1 , 可以去git下载下。

当然,我也是给你们备了的:


seata server 1.4.1


某度网盘分享地址:


https://pan.baidu.com/s/1R9McfkSkoj72Pf98ugCvBw


提取码:4ynp


第一步,下载下来解压 :


image.png



第二步,创个 seata server 用的数据库 :


 

CREATE TABLE `branch_table` (
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(128) NOT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `resource_group_id` varchar(32) DEFAULT NULL,
  `resource_id` varchar(256) DEFAULT NULL,
  `branch_type` varchar(8) DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  `client_id` varchar(64) DEFAULT NULL,
  `application_data` varchar(2000) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `gmt_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`branch_id`),
  KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `global_table` (
  `xid` varchar(128) NOT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `status` tinyint(4) NOT NULL,
  `application_id` varchar(32) DEFAULT NULL,
  `transaction_service_group` varchar(32) DEFAULT NULL,
  `transaction_name` varchar(128) DEFAULT NULL,
  `timeout` int(11) DEFAULT NULL,
  `begin_time` bigint(20) DEFAULT NULL,
  `application_data` varchar(2000) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `gmt_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`xid`),
  KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),
  KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `lock_table` (
  `row_key` varchar(128) NOT NULL,
  `xid` varchar(96) DEFAULT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `branch_id` bigint(20) NOT NULL,
  `resource_id` varchar(256) DEFAULT NULL,
  `table_name` varchar(32) DEFAULT NULL,
  `pk` varchar(36) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `gmt_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`row_key`),
  KEY `idx_branch_id` (`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


创建完后:


image.png


第三步,修改下 \seata-1.4.1\seata-server-1.4.1\seata\conf 里的配置文件一些信息 :


1. registry.conf


image.png


以上两个文件配置完(记得保存), 我们先把我们的注册中心 eureka服务跑起来,然后点击启动 seata server:


image.png


可以看到启动成功(前提是eureka已经启动):


image.png


第三步 ,配置我们需要用到 分布式事务 seata组件的 微服务 :


我这里的示例实践,需要用到的有2个微服务


image.png


那么我们这两个微服务都需要做点什么呢?


1. 在对应的微服务的对应的不同数据库里(只要你想用上seata的), 都加上undo_log 这个表:


image.png


SQL语句:


SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime(0) NULL,
  `log_modified` datetime(0) NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;


2. 关键步骤了 , 导入jar包 (需要用到seata组件都服务都需要导入)


    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-alibaba-seata</artifactId>
      <version>2.1.0.RELEASE</version>
      <exclusions>
        <exclusion>
          <artifactId>seata-all</artifactId>
          <groupId>io.seata</groupId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <artifactId>seata-all</artifactId>
      <groupId>io.seata</groupId>
      <version>1.4.1</version>
    </dependency>


3.更加关键了,就是做配置


先总得了解下,需要用到seata的 微服务需要做些什么配置 ?


1. 在resources 下 新增2个配置文件 , file.conf  和   registry.conf


2.yml 新增配置seata 事务组参数


3.代码调整数据源代理,交给seata代理



1.   registry.conf


 image.pngimage.png


以上是业务微服务里的registry.conf  需要改动的配置信息 ,给出一份该篇文章使用的:


 

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "eureka"
  loadBalance = "RandomLoadBalance"
  loadBalanceVirtualNodes = 10
  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = ""
    password = ""
  }
  eureka {
    serviceUrl = "http://localhost:8761/eureka/"
    application = "seata-server"
    weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = 0
    password = ""
    cluster = "default"
    timeout = 0
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
  }
  etcd3 {
    cluster = "default"
    serverAddr = "http://localhost:2379"
  }
  sofa {
    serverAddr = "127.0.0.1:9603"
    application = "default"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    cluster = "default"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  }
  file {
    name = "file.conf"
  }
}
config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "file"
  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = ""
    password = ""
  }
  consul {
    serverAddr = "127.0.0.1:8500"
  }
  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 = ""
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.conf"
  }
}


file.conf


image.png


给出一份该篇使用的完整的:


 

transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  # the client batch send request enable
  enableClientBatchSendRequest = true
  #thread factory for netty
  threadFactory {
    bossThreadPrefix = "NettyBoss"
    workerThreadPrefix = "NettyServerNIOWorker"
    serverExecutorThread-prefix = "NettyServerBizHandler"
    shareBossWorker = false
    clientSelectorThreadPrefix = "NettyClientSelector"
    clientSelectorThreadSize = 1
    clientWorkerThreadPrefix = "NettyClientWorkerThread"
    # netty boss thread size,will not be used for UDT
    bossThreadSize = 1
    #auto default pin or 8
    workerThreadSize = "default"
  }
  shutdown {
    # when destroy server, wait seconds
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}
service {
#这里注意,等号前后都是配置,前面是yml里配置的事务组,后面是register.conf里定义的seata-server
  vgroupMapping.test_tx_group = "seata-server"
  #only support when registry.type=file, please don't set multiple addresses
  seata_tc_server.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
    reportSuccessEnable = false
  }
  tm {
    commitRetryCount = 5
    rollbackRetryCount = 5
  }
  undo {
    dataValidation = true
    logSerialization = "jackson"
    logTable = "undo_log"
  }
  log {
    exceptionRate = 100
  }
}


2. 需要在yml配置文件加上配置项,指明当前服务使用了 seata分布式事务组件,且需要加入的分布式事务组是哪个:


image.png

spring:
  cloud:
    alibaba:
      seata.tx-service-group: test_tx_group


3.然后是需要将数据源交给seata去代理:

 

去掉默认自动加载数据源


配置dao层扫描位置


image.png

@MapperScan("com.cloud.client1.dao")
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)


然后是seata代理数据源(红色标注的地方需要注意下,都是实打实踩出来的坑。导入类的来源以及扫描的mapper的xml位置):


image.png


ok,到这里一个微服务 usercent的 整合 seata 分布式组件算是完成了。


同样,我们继续对 另外一个微服务 coredata 做seata 分布式组件  整合 。


也是第一步,file.conf 和 registry.conf  (其实我们现在就是让这两个微服务在同一个分布式事务组,我们直接把刚才在usercent那边的两个文件直接粘贴过来就好)。


然后第二步就是修改yml配置:


image.png


第三步就是新增seata数据源代理、application上的注解排除自动加载数据源和扫描dao层地址,yml上面的配置项:

image.png


完事,两个业务微服务都整合了 分布式事务组件 seata ,而且都设置在同个分布式事务组里 (test_tx_group).


那么到这其实已经完事了, 接下来玩下 分布式事务回滚场景 的例子 (怎么去使用)。


PS: 使用方式关注 @GlobalTransactional  注解, 想把全局事务从哪里开启,就把这个注解放到哪个方法上去, 这个方法内 调用的其他服务只要都使用了seata,且在同个事务组,那么就会加入到当前的全局事务里。


我该篇就不弄太多服务了,就弄了2个分布式服务。  


展示的例子内容 :

1. 上游服务 出错, 触发分布式事务, 上下游服务都会事务回滚;


2.下游服务 出错,触发分布式事务, 上下游服务都会事务回滚;(某种程度上讲,下游出错如果只有一个下游,其实不需分布式事务,通过错误传递单个回滚也是可以的。但是如果服务调用链很长,中游服务出错,需要整个链上的服务都事务回滚,那么就有必要都使用seata )


image.png


我们开始模拟:


第一个场景


上游服务 coredata 使用seata全局事务注解@GlobalTransactional 标记方法,先插入一个Account数据 ;


然后调用下游服务 usercent 插入一条数据;


然后 上游服务 coredata继续执行业务逻辑,继续插入数据;


接着模拟上游服务coredata开始报错(我们通过name长度故意触发错误);


期望结果:  上下游两个服务 在当前方法事务下插入的数据都回滚!


上游服务 coredata 方法:


image.png


通过fegin调用下游服务 usercent 方法:


image.png


下游服务 usercent 的插入方法:


image.png


开始模拟:


1.先把eureka跑起来:


image.png


暂时就注册中心自己,没有别的服务:


image.png


2.把seata server 服务跑起来,注册到eureka上去:

我是window环境,执行.bat


image.pngimage.png


可以看到已经成功注册到eureka上了:


image.png


3. 把上游微服务 coredata 和 下游服务 usercent 都跑起来:


image.png


然后看下seata server上,也可以看到 两个服务 都成功‘注册’到了 seata server上了,而且都在同一个事务组 test_tx_group里面:


image.png


接下来,就是开始调用一下我们模拟的场景代码就完事了(不过我会加点图来给大家简单分析下):


一开始,都是没有数据的:

image.png


调用上游服务coredata接口触发一下整个流程:


image.pngimage.png


调用开始:


我们打断点到 上游已经插入过一次数据,下游也插入过一次数据,


image.png


可以看到上游服务和下游服务的数据库里面的undo_log表出现了 事务记录,有关当前事务的 branch_id和 所在事务 xid,而且可以看到在两个服务内的undo_log表中记录的xid都是一致的,代表他们都在一个事务中:


image.png


然后我们继续往下执行,故意让上游报错:


image.pngimage.png


这时候,接口调用完毕结束:


我们看到seata server里面的信息,可以看到全局事务 xid为22080结尾,回滚成功:


image.png


回滚成功后,undo_log表中的记录会删除掉:


image.png

当然我们两个服务里面也是没有数据的,因为回滚了:


image.png


这里可能有人会想,你查一下是空就能证明是回滚了么?


这时候我们也可以利用主键自增当前值可以看到确实发生了数据回滚的场景:


image.png


第一个场景就到此吧。


接下来我们模拟第二个场景:


上游服务 coredata 使用seata全局事务注解@GlobalTransactional 标记方法,先插入一个Account数据 ;


然后调用下游服务 usercent 插入一条数据;


然后下游服务 直接模拟出错, 这样触发事务回滚。


期望结果:  上下游两个服务 在当前方法事务下插入的数据都回滚!


也就是说我们需要对下游服务的插入方法里面做手脚,故意抛出错误:


image.pngimage.png


快速调用一下:


image.png


可以看到下游出错了:


image.png


看下我们的seata server怎么说,已出发分布式事务,回滚成功:


image.png


数据库里面的数据也是回滚了,空的:


image.pngimage.png


好了,该篇springboot cloud使用eureka整合  分布式事务组件  Seata  就到此吧。


ps: 最近比较忙,每篇文章其实都是用一些零碎时间拼凑出来的。不过我会坚持我的文章的初衷,能让大家跟着实践,能搞懂,能学会。


我...只是个散工。

相关文章
|
1月前
|
监控 负载均衡 Java
5 大 SpringCloud 核心组件详解,8 张图彻底弄懂
本文图文详解 Spring Cloud 的五大核心组件,帮助深入理解和掌握微服务架构。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
5 大 SpringCloud 核心组件详解,8 张图彻底弄懂
|
27天前
|
Java 数据库
在Java中使用Seata框架实现分布式事务的详细步骤
通过以上步骤,利用 Seata 框架可以实现较为简单的分布式事务处理。在实际应用中,还需要根据具体业务需求进行更详细的配置和处理。同时,要注意处理各种异常情况,以确保分布式事务的正确执行。
|
14天前
|
消息中间件 SQL 中间件
大厂都在用的分布式事务方案,Seata+RocketMQ带你打破10万QPS瓶颈
分布式事务涉及跨多个数据库或服务的操作,确保数据一致性。本地事务通过数据库直接支持ACID特性,而分布式事务则需解决跨服务协调难、高并发压力及性能与一致性权衡等问题。常见的解决方案包括两阶段提交(2PC)、Seata提供的AT和TCC模式、以及基于消息队列的最终一致性方案。这些方法各有优劣,适用于不同业务场景,选择合适的方案需综合考虑业务需求、系统规模和技术团队能力。
103 7
|
26天前
|
存储 Java 关系型数据库
在Spring Boot中整合Seata框架实现分布式事务
可以在 Spring Boot 中成功整合 Seata 框架,实现分布式事务的管理和处理。在实际应用中,还需要根据具体的业务需求和技术架构进行进一步的优化和调整。同时,要注意处理各种可能出现的问题,以保障分布式事务的顺利执行。
46 6
|
26天前
|
数据库
如何在Seata框架中配置分布式事务的隔离级别?
总的来说,配置分布式事务的隔离级别是实现分布式事务管理的重要环节之一,需要认真对待和仔细调整,以满足业务的需求和性能要求。你还可以进一步深入研究和实践 Seata 框架的配置和使用,以更好地应对各种分布式事务场景的挑战。
28 6
|
24天前
|
消息中间件 运维 数据库
Seata框架和其他分布式事务框架有什么区别
Seata框架和其他分布式事务框架有什么区别
24 1
|
1月前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
82 5
|
2月前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
3月前
|
存储 NoSQL Redis
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
Redis持久化、RDB和AOF方案、Redis主从集群、哨兵、分片集群、散列插槽、自动手动故障转移
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
|
3月前
|
SQL NoSQL 数据库
SpringCloud基础6——分布式事务,Seata
分布式事务、ACID原则、CAP定理、Seata、Seata的四种分布式方案:XA、AT、TCC、SAGA模式
SpringCloud基础6——分布式事务,Seata