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

前言

SpringCloud 整合分布式事务组件 Seata (八)_第1张图片

 

近期一直在忙项目,我也是打工仔。不多说,我们开始玩一玩seata。


 

正文

 

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

 

SpringCloud 整合分布式事务组件 Seata (八)_第2张图片

 

简单一眼就看出来, 比我们平时用的东西,多了  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

第一步,下载下来解压 :

SpringCloud 整合分布式事务组件 Seata (八)_第3张图片

第二步,创个 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;

创建完后:

 

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

 

1. registry.conf

SpringCloud 整合分布式事务组件 Seata (八)_第4张图片

SpringCloud 整合分布式事务组件 Seata (八)_第5张图片

SpringCloud 整合分布式事务组件 Seata (八)_第6张图片

ok,registry.conf 这文件就修改这些配置项。

 

2. file.conf :

SpringCloud 整合分布式事务组件 Seata (八)_第7张图片

 

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

SpringCloud 整合分布式事务组件 Seata (八)_第8张图片

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

SpringCloud 整合分布式事务组件 Seata (八)_第9张图片

 

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

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

SpringCloud 整合分布式事务组件 Seata (八)_第10张图片

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

 

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

SpringCloud 整合分布式事务组件 Seata (八)_第11张图片

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组件都服务都需要导入)

		
			com.alibaba.cloud
			spring-cloud-alibaba-seata
			2.1.0.RELEASE
			
				
					seata-all
					io.seata
				
			
		
		
			seata-all
			io.seata
			1.4.1
		

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

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

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

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

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

 

1.   registry.conf  

SpringCloud 整合分布式事务组件 Seata (八)_第12张图片

SpringCloud 整合分布式事务组件 Seata (八)_第13张图片

以上是业务微服务里的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

SpringCloud 整合分布式事务组件 Seata (八)_第14张图片

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

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分布式事务组件,且需要加入的分布式事务组是哪个: 

SpringCloud 整合分布式事务组件 Seata (八)_第15张图片

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

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

去掉默认自动加载数据源

配置dao层扫描位置

SpringCloud 整合分布式事务组件 Seata (八)_第16张图片

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

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

SpringCloud 整合分布式事务组件 Seata (八)_第17张图片

 

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

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

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

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

SpringCloud 整合分布式事务组件 Seata (八)_第18张图片

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

SpringCloud 整合分布式事务组件 Seata (八)_第19张图片

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

 

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

 

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

展示的例子内容 :


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

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

 

我们开始模拟: 

第一个场景

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

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

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

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

 

 

上游服务 coredata 方法:

SpringCloud 整合分布式事务组件 Seata (八)_第20张图片

通过fegin调用下游服务 usercent 方法:
SpringCloud 整合分布式事务组件 Seata (八)_第21张图片

下游服务 usercent 的插入方法:

SpringCloud 整合分布式事务组件 Seata (八)_第22张图片

 

开始模拟:

 

1.先把eureka跑起来:
SpringCloud 整合分布式事务组件 Seata (八)_第23张图片

暂时就注册中心自己,没有别的服务:
SpringCloud 整合分布式事务组件 Seata (八)_第24张图片

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

我是window环境,执行.bat
SpringCloud 整合分布式事务组件 Seata (八)_第25张图片

SpringCloud 整合分布式事务组件 Seata (八)_第26张图片

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

SpringCloud 整合分布式事务组件 Seata (八)_第27张图片

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

SpringCloud 整合分布式事务组件 Seata (八)_第28张图片

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

SpringCloud 整合分布式事务组件 Seata (八)_第29张图片

 

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

 

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

SpringCloud 整合分布式事务组件 Seata (八)_第30张图片

调用上游服务coredata接口触发一下整个流程:
SpringCloud 整合分布式事务组件 Seata (八)_第31张图片

SpringCloud 整合分布式事务组件 Seata (八)_第32张图片

 

调用开始:

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

SpringCloud 整合分布式事务组件 Seata (八)_第33张图片

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

SpringCloud 整合分布式事务组件 Seata (八)_第34张图片

然后我们继续往下执行,故意让上游报错:
SpringCloud 整合分布式事务组件 Seata (八)_第35张图片

SpringCloud 整合分布式事务组件 Seata (八)_第36张图片

这时候,接口调用完毕结束:
我们看到seata server里面的信息,可以看到全局事务 xid为22080结尾,回滚成功:

回滚成功后,undo_log表中的记录会删除掉:
SpringCloud 整合分布式事务组件 Seata (八)_第37张图片

当然我们两个服务里面也是没有数据的,因为回滚了:
SpringCloud 整合分布式事务组件 Seata (八)_第38张图片

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

这时候我们也可以利用主键自增当前值可以看到确实发生了数据回滚的场景:
SpringCloud 整合分布式事务组件 Seata (八)_第39张图片

 

第一个场景就到此吧。

 

 

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

 

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

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

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

也就是说我们需要对下游服务的插入方法里面做手脚,故意抛出错误:
SpringCloud 整合分布式事务组件 Seata (八)_第40张图片

 

SpringCloud 整合分布式事务组件 Seata (八)_第41张图片

 

快速调用一下:

SpringCloud 整合分布式事务组件 Seata (八)_第42张图片

可以看到下游出错了:

SpringCloud 整合分布式事务组件 Seata (八)_第43张图片

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

SpringCloud 整合分布式事务组件 Seata (八)_第44张图片

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

SpringCloud 整合分布式事务组件 Seata (八)_第45张图片

SpringCloud 整合分布式事务组件 Seata (八)_第46张图片

 

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



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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(带你从零掌握,SpringCloud,跟我一起玩转,SpringBoot,springcloud,seata,分布式事务,eureka)