springboot cloud使用eureka整合分布式事務(wù)組件Seata 的方法
前言
近期一直在忙項(xiàng)目,我也是打工仔。不多說(shuō),我們開(kāi)始玩一玩seata。
正文
什么都不說(shuō),我們按照慣例,先上一個(gè)圖(圖里不規(guī)范的使用請(qǐng)忽略):
簡(jiǎn)單一眼就看出來(lái), 比我們平時(shí)用的東西,多了 Seata Server 微服務(wù) 。
同樣這個(gè) Seata Server 微服務(wù) ,也是需要注冊(cè)到eureka上面去的。
那么我們首先就搞一搞這個(gè) seata server ,那么剩下的就是一些原本的業(yè)務(wù)服務(wù)整合配置了。
該篇用的 seata server 版本,用的是1.4.1 , 可以去git下載下。當(dāng)然,我也是給你們備了的:
seata server 1.4.1 某度網(wǎng)盤(pán)分享地址:
鏈接: https://pan.baidu.com/s/1Oj1NkKwU4jeLjJ3Pu9hT2Q
提取碼: 9at6
第一步,下載下來(lái)解壓 :
第二步,創(chuàng)個(gè) seata server 用的數(shù)據(jù)庫(kù) :
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;
創(chuàng)建完后:
第三步,修改下 \seata-1.4.1\seata-server-1.4.1\seata\conf 里的配置文件一些信息 :
1. registry.conf
ok,registry.conf 這文件就修改這些配置項(xiàng)。
2. file.conf :
以上兩個(gè)文件配置完(記得保存), 我們先把我們的注冊(cè)中心 eureka服務(wù)跑起來(lái),然后點(diǎn)擊啟動(dòng) seata server:
可以看到啟動(dòng)成功(前提是eureka已經(jīng)啟動(dòng)):
第三步 ,配置我們需要用到 分布式事務(wù) seata組件的 微服務(wù) :
我這里的示例實(shí)踐,需要用到的有2個(gè)微服務(wù) :
那么我們這兩個(gè)微服務(wù)都需要做點(diǎn)什么呢?
1. 在對(duì)應(yīng)的微服務(wù)的對(duì)應(yīng)的不同數(shù)據(jù)庫(kù)里(只要你想用上seata的), 都加上undo_log 這個(gè)表:
SQL語(yǔ)句:
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. 關(guān)鍵步驟了 , 導(dǎo)入jar包 (需要用到seata組件都服務(wù)都需要導(dǎo)入)
<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.更加關(guān)鍵了,就是做配置
先總得了解下,需要用到seata的 微服務(wù)需要做些什么配置 ?
1. 在resources 下 新增2個(gè)配置文件 , file.conf 和 registry.conf
2.yml 新增配置seata 事務(wù)組參數(shù)
3.代碼調(diào)整數(shù)據(jù)源代理,交給seata代理
1. registry.conf
以上是業(yè)務(wù)微服務(wù)里的registry.conf 需要改動(dòng)的配置信息 ,給出一份該篇文章使用的:
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
給出一份該篇使用的完整的:
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 { #這里注意,等號(hào)前后都是配置,前面是yml里配置的事務(wù)組,后面是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配置文件加上配置項(xiàng),指明當(dāng)前服務(wù)使用了 seata分布式事務(wù)組件,且需要加入的分布式事務(wù)組是哪個(gè):
spring: cloud: alibaba: seata.tx-service-group: test_tx_group
3.然后是需要將數(shù)據(jù)源交給seata去代理:
去掉默認(rèn)自動(dòng)加載數(shù)據(jù)源
配置dao層掃描位置
@MapperScan("com.cloud.client1.dao") @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
然后是seata代理數(shù)據(jù)源(紅色標(biāo)注的地方需要注意下,都是實(shí)打?qū)嵅瘸鰜?lái)的坑。導(dǎo)入類的來(lái)源以及掃描的mapper的xml位置):
ok,到這里一個(gè)微服務(wù) usercent的 整合 seata 分布式組件算是完成了。
同樣,我們繼續(xù)對(duì) 另外一個(gè)微服務(wù) coredata 做seata 分布式組件 整合 。
也是第一步,file.conf 和 registry.conf (其實(shí)我們現(xiàn)在就是讓這兩個(gè)微服務(wù)在同一個(gè)分布式事務(wù)組,我們直接把剛才在usercent那邊的兩個(gè)文件直接粘貼過(guò)來(lái)就好)。
然后第二步就是修改yml配置:
第三步就是新增seata數(shù)據(jù)源代理、application上的注解排除自動(dòng)加載數(shù)據(jù)源和掃描dao層地址,yml上面的配置項(xiàng):
完事,兩個(gè)業(yè)務(wù)微服務(wù)都整合了 分布式事務(wù)組件 seata ,而且都設(shè)置在同個(gè)分布式事務(wù)組里 (test_tx_group).
那么到這其實(shí)已經(jīng)完事了, 接下來(lái)玩下 分布式事務(wù)回滾場(chǎng)景 的例子 (怎么去使用)。
我該篇就不弄太多服務(wù)了,就弄了2個(gè)分布式服務(wù)。
展示的例子內(nèi)容 :
1. 上游服務(wù) 出錯(cuò), 觸發(fā)分布式事務(wù), 上下游服務(wù)都會(huì)事務(wù)回滾;
2.下游服務(wù) 出錯(cuò),觸發(fā)分布式事務(wù), 上下游服務(wù)都會(huì)事務(wù)回滾;(某種程度上講,下游出錯(cuò)如果只有一個(gè)下游,其實(shí)不需分布式事務(wù),通過(guò)錯(cuò)誤傳遞單個(gè)回滾也是可以的。但是如果服務(wù)調(diào)用鏈很長(zhǎng),中游服務(wù)出錯(cuò),需要整個(gè)鏈上的服務(wù)都事務(wù)回滾,那么就有必要都使用seata )
我們開(kāi)始模擬:
第一個(gè)場(chǎng)景 上游服務(wù) coredata 使用seata全局事務(wù)注解@GlobalTransactional 標(biāo)記方法,先插入一個(gè)Account數(shù)據(jù) ;然后調(diào)用下游服務(wù) usercent 插入一條數(shù)據(jù);
然后 上游服務(wù) coredata繼續(xù)執(zhí)行業(yè)務(wù)邏輯,繼續(xù)插入數(shù)據(jù);
接著模擬上游服務(wù)coredata開(kāi)始報(bào)錯(cuò)(我們通過(guò)name長(zhǎng)度故意觸發(fā)錯(cuò)誤);
期望結(jié)果: 上下游兩個(gè)服務(wù) 在當(dāng)前方法事務(wù)下插入的數(shù)據(jù)都回滾!
上游服務(wù) coredata 方法:
通過(guò)fegin調(diào)用下游服務(wù) usercent 方法:
下游服務(wù) usercent 的插入方法:
開(kāi)始模擬:
1.先把eureka跑起來(lái):
暫時(shí)就注冊(cè)中心自己,沒(méi)有別的服務(wù):
2.把seata server 服務(wù)跑起來(lái),注冊(cè)到eureka上去:
我是window環(huán)境,執(zhí)行.bat
可以看到已經(jīng)成功注冊(cè)到eureka上了:
3. 把上游微服務(wù) coredata 和 下游服務(wù) usercent 都跑起來(lái):
然后看下seata server上,也可以看到 兩個(gè)服務(wù) 都成功‘注冊(cè)'到了 seata server上了,而且都在同一個(gè)事務(wù)組 test_tx_group里面:
接下來(lái),就是開(kāi)始調(diào)用一下我們模擬的場(chǎng)景代碼就完事了(不過(guò)我會(huì)加點(diǎn)圖來(lái)給大家簡(jiǎn)單分析下):
一開(kāi)始,都是沒(méi)有數(shù)據(jù)的:
調(diào)用上游服務(wù)coredata接口觸發(fā)一下整個(gè)流程:
調(diào)用開(kāi)始:
我們打斷點(diǎn)到 上游已經(jīng)插入過(guò)一次數(shù)據(jù),下游也插入過(guò)一次數(shù)據(jù),
可以看到上游服務(wù)和下游服務(wù)的數(shù)據(jù)庫(kù)里面的undo_log表出現(xiàn)了 事務(wù)記錄,有關(guān)當(dāng)前事務(wù)的 branch_id和 所在事務(wù) xid,而且可以看到在兩個(gè)服務(wù)內(nèi)的undo_log表中記錄的xid都是一致的,代表他們都在一個(gè)事務(wù)中:
然后我們繼續(xù)往下執(zhí)行,故意讓上游報(bào)錯(cuò):
這時(shí)候,接口調(diào)用完畢結(jié)束:我們看到seata server里面的信息,可以看到全局事務(wù) xid為22080結(jié)尾,回滾成功:
回滾成功后,undo_log表中的記錄會(huì)刪除掉:
當(dāng)然我們兩個(gè)服務(wù)里面也是沒(méi)有數(shù)據(jù)的,因?yàn)榛貪L了:
這里可能有人會(huì)想,你查一下是空就能證明是回滾了么?
這時(shí)候我們也可以利用主鍵自增當(dāng)前值可以看到確實(shí)發(fā)生了數(shù)據(jù)回滾的場(chǎng)景:
第一個(gè)場(chǎng)景就到此吧。
接下來(lái)我們模擬第二個(gè)場(chǎng)景:
上游服務(wù) coredata 使用seata全局事務(wù)注解@GlobalTransactional 標(biāo)記方法,先插入一個(gè)Account數(shù)據(jù) ;然后調(diào)用下游服務(wù) usercent 插入一條數(shù)據(jù);
然后下游服務(wù) 直接模擬出錯(cuò), 這樣觸發(fā)事務(wù)回滾。 期望結(jié)果: 上下游兩個(gè)服務(wù) 在當(dāng)前方法事務(wù)下插入的數(shù)據(jù)都回滾!
也就是說(shuō)我們需要對(duì)下游服務(wù)的插入方法里面做手腳,故意拋出錯(cuò)誤:
快速調(diào)用一下:
可以看到下游出錯(cuò)了:
看下我們的seata server怎么說(shuō),已出發(fā)分布式事務(wù),回滾成功:
數(shù)據(jù)庫(kù)里面的數(shù)據(jù)也是回滾了,空的:
好了,該篇springboot cloud使用eureka整合 分布式事務(wù)組件 Seata 就到此吧。
ps: 最近比較忙,每篇文章其實(shí)都是用一些零碎時(shí)間拼湊出來(lái)的。不過(guò)我會(huì)堅(jiān)持我的文章的初衷,能讓大家跟著實(shí)踐,能搞懂,能學(xué)會(huì)。我...只是個(gè)散工。
到此這篇關(guān)于SpringCloud 整合分布式事務(wù)組件 Seata的文章就介紹到這了,更多相關(guān)SpringCloud 整合分布式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Java中布隆過(guò)濾器(Bloom Filter)原理及其使用場(chǎng)景
布隆過(guò)濾器是1970年由布隆提出的,它實(shí)際上是一個(gè)很長(zhǎng)的二進(jìn)制向量和一系列隨機(jī)映射函數(shù),它的作用是檢索一個(gè)元素是否存在我們的集合之中,本文給大家詳細(xì)的講解一下布隆過(guò)濾器,感興趣的同學(xué)可以參考閱讀2023-05-05如何使用Java語(yǔ)言編寫(xiě)打地鼠游戲全過(guò)程
打地鼠是我們非常熟悉的一款小游戲,它的游戲結(jié)構(gòu)和規(guī)則也都比較簡(jiǎn)單,那么如果能夠親自徒手開(kāi)發(fā)這樣的一款經(jīng)典小游戲呢?這篇文章主要給大家介紹了關(guān)于如何使用Java語(yǔ)言編寫(xiě)打地鼠游戲的相關(guān)資料,需要的朋友可以參考下2024-06-06JAVA中HTTP基本認(rèn)證(Basic Authentication)實(shí)現(xiàn)
HTTP 基本認(rèn)證是一種簡(jiǎn)單的認(rèn)證方法,本文主要介紹了JAVA中HTTP基本認(rèn)證(Basic Authentication),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07Spring Data Jpa實(shí)現(xiàn)分頁(yè)和排序代碼實(shí)例
本篇文章主要介紹了Spring Data Jpa實(shí)現(xiàn)分頁(yè)和排序代碼實(shí)例,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-03-03SpringBoot封裝響應(yīng)數(shù)據(jù)實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了SpringBoot封裝響應(yīng)數(shù)據(jù)實(shí)現(xiàn)過(guò)程,SpringBoot響應(yīng)數(shù)據(jù)封裝是指在SpringBoot應(yīng)用程序中,將返回的數(shù)據(jù)進(jìn)行封裝,以便于前端頁(yè)面或其他客戶端使用,感興趣想要詳細(xì)了解可以參考下文2023-05-05SpringCloud Zuul過(guò)濾器和谷歌Gauva實(shí)現(xiàn)限流
這篇文章主要介紹了SpringCloud Zuul過(guò)濾器和谷歌Gauva實(shí)現(xiàn)限流,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03Java更新調(diào)度器(update scheduler)的使用詳解
Java更新調(diào)度器是Java中的一個(gè)特性,可以自動(dòng)化Java應(yīng)用程序的更新過(guò)程,它提供了一種方便的方式來(lái)安排Java應(yīng)用程序的更新,確保其與最新的功能、錯(cuò)誤修復(fù)和安全補(bǔ)丁保持同步,本文將深入介紹如何使用Java更新調(diào)度器,并解釋它對(duì)Java開(kāi)發(fā)人員和用戶的好處2023-11-11