国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
分布式事務(wù)之解決方案(XA和2PC)

3. 分布式事務(wù)解決方案之2PC(兩階段提交)

針對(duì)不同的分布式場景業(yè)界常見的解決方案有2PC、TCC、可靠消息最終一致性、最大努力通知這幾種。

3.1. 什么是2PC

2PC即兩階段提交協(xié)議,是將整個(gè)事務(wù)流程分為兩個(gè)階段,準(zhǔn)備階段(Prepare phase)、提交階段(commit phase),2是指兩階段,P是指準(zhǔn)備階段,C是提交階段。
舉例 :張三和李四好久不見,老友約起聚餐,飯店老板要求先買單,才能出票。這時(shí)張三和李四分別抱怨近況不如意,囊腫羞澀,都不愿意請(qǐng)客,這時(shí)只能AA。只有張三和李四都付款,老板才能出票安排就餐。但由于張三和李四都是鐵公雞,形成兩尷尬的一幕 :
準(zhǔn)備階段 :老板要求張三付款,張三付款。老板要求李四付款,李四付款。
提交階段 :老板出票,兩人拿票紛紛落座就餐。
例子中形成兩一個(gè)事務(wù),若張三或李四其中一個(gè)拒絕付款,或錢不夠,店老板都不會(huì)給出票,并且會(huì)把已收款退回。
整個(gè)事務(wù)過程由事務(wù)管理器和參與者組成,店老板就是事務(wù)管理器,張三、李四就是事務(wù)參與者,事務(wù)管理器負(fù)責(zé)決策整個(gè)分布式事務(wù)的提交和回滾,事務(wù)參與者負(fù)責(zé)自己本地事務(wù)的提交和回滾。
在計(jì)算機(jī)中部分關(guān)系數(shù)據(jù)庫如Oracle、MySQL支持兩階段提交協(xié)議,如下圖 :
1. 準(zhǔn)備階段(Prepare phase):事務(wù)管理器給每個(gè)參與者發(fā)送Prepare消息,每個(gè)數(shù)據(jù)庫參與者在本地執(zhí)行事務(wù),并寫本地的Undo/Redo日志,此時(shí)事務(wù)沒有提交。
(Undo日志是記錄修改前的數(shù)據(jù),用于數(shù)據(jù)庫回滾,Redo日志是記錄修改后的數(shù)據(jù),用于提交事務(wù)后寫入數(shù)據(jù)文件)
2. 提交階段(commit phase):如果事務(wù)管理器收到兩參與者的執(zhí)行失敗或者超時(shí)消息時(shí),直接給每個(gè)參與者發(fā)送回滾(Rollback)消息;否則,發(fā)送提交(Commit)消息;參與者根據(jù)事務(wù)管理器的指令執(zhí)行提交或者回滾操作,并釋放事務(wù)處理過程中使用的鎖資源。注意 :必須在最后階段釋放鎖資源。
下圖展示兩2PC的兩個(gè)階段,分成功和失敗兩個(gè)情況說明 :
成功情況 :


在這里插入圖片描述

失敗情況 :


在這里插入圖片描述

3.2. 解決方案

3.2.1 XA方案

2PC的傳統(tǒng)方案是在數(shù)據(jù)庫層面實(shí)現(xiàn)的,如Oracle、MySQL都支持2PC協(xié)議,為了統(tǒng)一標(biāo)準(zhǔn)減少行業(yè)內(nèi)不必要的對(duì)接成本,需要制定標(biāo)準(zhǔn)化的處理模型及接口標(biāo)準(zhǔn),國際開放標(biāo)準(zhǔn)組織Open Group定義分布式事務(wù)處理模型DTP(Distributed Transaction Processing Reference Model)。
為了讓大家更明確XA方案的內(nèi)容,下面新用戶注冊(cè)送積分為例來說明 :

在這里插入圖片描述

執(zhí)行流程如下 :
1、應(yīng)用程序(AP)持有用戶庫和積分庫兩個(gè)數(shù)據(jù)源。
2、應(yīng)用程序(AP)通過TM通知用戶庫RM新增用戶,同時(shí)通知積分庫RM為該用戶新增積分,RM此時(shí)并未提交事務(wù),此時(shí)用戶和積分資源鎖定。
3、TM收到執(zhí)行回復(fù),只要有一方失敗則分別向其他RM發(fā)起回滾事務(wù),回滾完畢,資源鎖釋放。
4、TM收到執(zhí)行回復(fù),全部成功,此時(shí)向所有RM發(fā)起提交事務(wù),提交完畢,資源鎖釋放。
DTP模型定義如下角色 :
  • AP(Application Program) : 既應(yīng)用程序,可以理解為使用DTP分布式事務(wù)的程序。

  • RM(Resource Manager) : 即資源管理器,可以理解為事務(wù)的參與者,一般情況下是指一個(gè)數(shù)據(jù)庫實(shí)例,通過資源管理器對(duì)該數(shù)據(jù)庫進(jìn)行控制,資源管理器控制著分支事務(wù)。

  • TM(Transaction Manager) : 事務(wù)管理器,負(fù)責(zé)協(xié)調(diào)和管理事務(wù),事務(wù)管理器控制著全局事務(wù),管理事務(wù)生命周期,并協(xié)調(diào)各個(gè)RM。全局事務(wù)是指分布式事務(wù)處理環(huán)境中,需要操作多個(gè)數(shù)據(jù)庫共同完成一個(gè)工作,這個(gè)工作即是一個(gè)全局事務(wù)。

  • DTP模型定義TM和RM之間通訊的接口規(guī)范叫XA,簡單理解為數(shù)據(jù)庫提供的2PC接口協(xié)議,基于數(shù)據(jù)庫的XA協(xié)議來實(shí)現(xiàn)2PC又稱為XA方案。

  • 以上三個(gè)角色之間的交互方式如下 :
    1)TM向AP提供應(yīng)用程序編程接口,AP通過TM提交及回滾事務(wù)。
    2)TM交易中間件通過XA接口來通知RM數(shù)據(jù)庫事務(wù)的開始、結(jié)束以及提交、回滾等。
    總結(jié) :
    整個(gè)2PC的事務(wù)流程涉及到三個(gè)角色AP、RM、TM。AP指的是使用2PC分布式事務(wù)的應(yīng)用程序;RM指的是資源管理器,它控制著分支事務(wù);TM指的是事務(wù)管理器,它控制著整個(gè)全局事務(wù)。
    1)在準(zhǔn)備階段RM執(zhí)行實(shí)際的業(yè)務(wù)操作,但不提交事務(wù),資源鎖定;
    2)在提交階段TM會(huì)接收RM在準(zhǔn)備階段的執(zhí)行回復(fù),只要有任一個(gè)RM執(zhí)行失敗,TM會(huì)通知所有RM執(zhí)行回滾操作,否則,TM將會(huì)通知所有RM提交該事務(wù)。提交階段結(jié)束資源鎖釋放。
    XA方案的問題 :
    1、需要本地?cái)?shù)據(jù)庫支持XA協(xié)議。
    2、資源鎖需要等到兩個(gè)階段結(jié)束才釋放,性能較差。

3.2.2 Seata方案

Seata是阿里中間件團(tuán)隊(duì)發(fā)起的開源項(xiàng)目Fescar,后更名Seata,它是一個(gè)是開源的分布式事務(wù)框架。傳統(tǒng)2PC的問題在Seata中得到了解決,它通過對(duì)本地關(guān)系數(shù)據(jù)庫的分支事務(wù)的協(xié)調(diào)來驅(qū)動(dòng)完成全局事務(wù),是工作在應(yīng)用層的中間件。主要優(yōu)點(diǎn)是性能較好,且不長時(shí)間占用連接資源,它以高效并且對(duì)業(yè)務(wù)0入侵的方式解決微服務(wù)場景下面臨的分布式事務(wù)問題,它目前提供AT模式(即2PC)及TCC模式的分布式事務(wù)解決方案。
Seata的設(shè)計(jì)思想如下 :
Seata的設(shè)計(jì)目標(biāo)其一是對(duì)業(yè)務(wù)無入侵,因此從業(yè)務(wù)無入侵的2PC方案著手,在傳統(tǒng)2PC的基礎(chǔ)上演進(jìn),并解決2PC方案面臨的問題。
Seata把一個(gè)分布式事務(wù)理解成一個(gè)包含來若干分支事務(wù)的全局事務(wù)。全局事務(wù)的職責(zé)是協(xié)調(diào)其下管轄的分支事務(wù)達(dá)成一致,要么一起成功提交,要么一起失敗回滾。此外,通常分支事務(wù)本身就是一個(gè)關(guān)系數(shù)據(jù)庫的本地事務(wù),下圖是全局事務(wù)與分支事務(wù)的關(guān)系圖 :

在這里插入圖片描述

與傳統(tǒng)2PC的模型類似,Seata定義了三個(gè)組件來協(xié)議分布式事務(wù)的處理過程 :
在這里插入圖片描述
  • Transaction Coordinator(TC):事務(wù)協(xié)調(diào)器,它是獨(dú)立的中間件,需要獨(dú)立部署運(yùn)行,它維護(hù)全局事務(wù)的運(yùn)行狀態(tài),接收TM指令發(fā)起全局事務(wù)的提交與回滾,負(fù)責(zé)與RM通信協(xié)調(diào)各個(gè)分支事務(wù)的提交或回滾。

  • Transaction Manager(TM):事務(wù)管理器,TM需要嵌入應(yīng)用程序中工作,它負(fù)責(zé)開啟一個(gè)全局事務(wù),并最終向TC發(fā)起全局提交或全局回滾的指令。

  • Resource Manager(RM):控制分支事務(wù),負(fù)責(zé)分支注冊(cè)、狀態(tài)匯報(bào),并接收事務(wù)協(xié)調(diào)器TC的指令,驅(qū)動(dòng)分支(本地)事務(wù)的提交和回滾。
    還拿新用戶注冊(cè)送積分舉例Seata的分布式事務(wù)過程 :

    在這里插入圖片描述

    具體的執(zhí)行流程如下 :

  1. 用戶服務(wù)的TM向TC申請(qǐng)開啟一個(gè)全局事務(wù),全局事務(wù)創(chuàng)建成功并生成一個(gè)全局唯一的XID。

  2. 用戶服務(wù)的RM向TC注冊(cè)分支事務(wù),該分支事務(wù)在用戶服務(wù)執(zhí)行新增用戶邏輯,并將其納入XID對(duì)應(yīng)全局事務(wù)的管轄。

  3. 用戶服務(wù)執(zhí)行分支事務(wù),向用戶表插入一條記錄。

  4. 邏輯執(zhí)行到遠(yuǎn)程調(diào)用積分服務(wù)時(shí)(XID在微服務(wù)調(diào)用鏈路的上下文中傳播)。積分服務(wù)的RM向TC注冊(cè)分支事務(wù),該分支事務(wù)執(zhí)行增加積分的邏輯,并將其納入XID對(duì)應(yīng)全局事務(wù)的管轄。

  5. 積分服務(wù)執(zhí)行分支事務(wù),向積分記錄表插入一條記錄,執(zhí)行完畢后,返回用戶服務(wù)。

  6. 用戶服務(wù)分支事務(wù)執(zhí)行完畢。

  7. TM向TC發(fā)起針對(duì)XID的全局提交或回滾決議。

  8. TC調(diào)度XID下管轄的全部分支事務(wù)完成提交或回滾請(qǐng)求。

Seata實(shí)現(xiàn)2PC與傳統(tǒng)2PC的差別 :
架構(gòu)層次方面,傳統(tǒng)2PC方案的RM實(shí)際上是在數(shù)據(jù)庫層,RM本質(zhì)上就是數(shù)據(jù)庫自身,通過XA協(xié)議實(shí)現(xiàn),而Seata的RM是以jar包的形式作為中間件層部署在應(yīng)用程序的這一側(cè)的。
兩階段提交方面,傳統(tǒng)2PC無論第二階段的決議是commit還是rollbcak,事務(wù)性資源的鎖都要保持到Phase2完成才釋放。而Seata的做法是在Phase1就將本地事務(wù)提交,這樣就可以省去Phase2持鎖的時(shí)間,整體提高效率。

3.3. Seata實(shí)現(xiàn)2PC事務(wù)

3.3.1. 業(yè)務(wù)說明

本實(shí)例通過Seata中間件實(shí)現(xiàn)分布式事務(wù),模擬兩個(gè)賬戶的轉(zhuǎn)賬交易過程。兩個(gè)賬戶在兩個(gè)不同的銀行(張三在bank1、李四在bank2),bank1和bank2是兩個(gè)微服務(wù)。交易過程中,張三給李四轉(zhuǎn)賬制定金額。
上述交易步驟,要么一起成功,要么一起失敗,必須是一個(gè)整體性的事務(wù)。


在這里插入圖片描述

3.3.2.程序組成部分

本實(shí)例程序組成 部分如下 :
數(shù)據(jù)庫 :MySQL-5.7.25
包括bank1和bank2兩個(gè)數(shù)據(jù)庫。
JDK:1.8
微服務(wù)框架 :spring-boot-2.1.3、spring-cloud-Greenwich.RELEASE
seata客戶端(RM、TM):spring-cloud-alibaba-seata-2.1.0RELEASE
seata服務(wù)端(TC):seata-server-0.7.1
微服務(wù)及數(shù)據(jù)庫的關(guān)系 :
dtx/dtx-seata-demo/seata-demo-bank1 銀行1,操作張三賬戶,鏈接數(shù)據(jù)庫bank1
dtx/dtx-seata-demo/seata-demo-bank2 銀行2,操作李四賬戶,鏈接數(shù)據(jù)庫bank2
服務(wù)注冊(cè)中興 :dtx/discover-server
本實(shí)例程序技術(shù)架構(gòu)如下 :


在這里插入圖片描述

交互流程如下 :
1、請(qǐng)求bank1進(jìn)行轉(zhuǎn)賬,傳入轉(zhuǎn)賬金額。
2、bank1減少轉(zhuǎn)賬金額,調(diào)用bank2,傳入轉(zhuǎn)賬金額。

3.3.3.創(chuàng)建數(shù)據(jù)庫

bank1庫,包含張三賬戶

CREATE DATABASE /*!32312 IF NOT EXISTS*/`bank1` /*!40100 DEFAULT CHARACTER SET utf8 */;USE `bank1`;/*Table structure for table `account_info` */DROP TABLE IF EXISTS `account_info`;CREATE TABLE `account_info` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `account_name` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '戶主姓名',  `account_no` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '銀行卡號(hào)',  `account_password` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '帳戶密碼',  `account_balance` double DEFAULT NULL COMMENT '帳戶余額',  PRIMARY KEY (`id`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;/*Data for the table `account_info` */insert  into `account_info`(`id`,`account_name`,`account_no`,`account_password`,`account_balance`) values (2,'張三','1',NULL,1000);/*Table structure for table `de_duplication` */DROP TABLE IF EXISTS `de_duplication`;CREATE TABLE `de_duplication` (  `tx_no` varchar(64) COLLATE utf8_bin NOT NULL,  `create_time` datetime DEFAULT NULL,  PRIMARY KEY (`tx_no`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;/*Data for the table `de_duplication` *//*Table structure for table `local_cancel_log` */DROP TABLE IF EXISTS `local_cancel_log`;CREATE TABLE `local_cancel_log` (  `tx_no` varchar(64) NOT NULL COMMENT '事務(wù)id',  `create_time` datetime DEFAULT NULL,  PRIMARY KEY (`tx_no`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `local_cancel_log` *//*Table structure for table `local_confirm_log` */DROP TABLE IF EXISTS `local_confirm_log`;CREATE TABLE `local_confirm_log` (  `tx_no` varchar(64) NOT NULL COMMENT '事務(wù)id',  `create_time` datetime DEFAULT NULL,  PRIMARY KEY (`tx_no`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `local_confirm_log` *//*Table structure for table `local_trade_log` */DROP TABLE IF EXISTS `local_trade_log`;CREATE TABLE `local_trade_log` (  `tx_no` bigint(20) NOT NULL,  `create_time` datetime DEFAULT NULL,  PRIMARY KEY (`tx_no`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;DROP TABLE IF EXISTS `local_try_log`;CREATE TABLE `local_try_log` (  `tx_no` varchar(64) NOT NULL COMMENT '事務(wù)id',  `create_time` datetime DEFAULT NULL,  PRIMARY KEY (`tx_no`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `local_try_log` *//*Table structure for table `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) NOT NULL,  `context` varchar(128) NOT NULL,  `rollback_info` longblob NOT NULL,  `log_status` int(11) NOT NULL,  `log_created` datetime NOT NULL,  `log_modified` datetime NOT NULL,  `ext` varchar(100) DEFAULT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)) ENGINE=InnoDB AUTO_INCREMENT=167 DEFAULT CHARSET=utf8;/*Data for the table `undo_log` */insert  into `undo_log`(`id`,`branch_id`,`xid`,`context`,`rollback_info`,`log_status`,`log_created`,`log_modified`,`ext`) values (166,2019228885,'192.168.1.101:8888:2019228047','serializer=jackson','{}',1,'2019-08-11 15:16:43','2019-08-11 15:16:43',NULL);

bank2庫,包含李四賬戶

CREATE DATABASE /*!32312 IF NOT EXISTS*/`bank2` /*!40100 DEFAULT CHARACTER SET utf8 */;USE `bank2`;/*Table structure for table `account_info` */DROP TABLE IF EXISTS `account_info`;CREATE TABLE `account_info` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `account_name` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '戶主姓名',  `account_no` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '銀行卡號(hào)',  `account_password` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '帳戶密碼',  `account_balance` double DEFAULT NULL COMMENT '帳戶余額',  PRIMARY KEY (`id`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;/*Data for the table `account_info` */insert  into `account_info`(`id`,`account_name`,`account_no`,`account_password`,`account_balance`) values (3,'李四的賬戶','2',NULL,0);/*Table structure for table `de_duplication` */DROP TABLE IF EXISTS `de_duplication`;CREATE TABLE `de_duplication` (  `tx_no` varchar(64) COLLATE utf8_bin NOT NULL,  `create_time` datetime DEFAULT NULL,  PRIMARY KEY (`tx_no`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;/*Data for the table `de_duplication` *//*Table structure for table `local_cancel_log` */DROP TABLE IF EXISTS `local_cancel_log`;CREATE TABLE `local_cancel_log` (  `tx_no` varchar(64) NOT NULL COMMENT '事務(wù)id',  `create_time` datetime DEFAULT NULL,  PRIMARY KEY (`tx_no`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `local_cancel_log` *//*Table structure for table `local_confirm_log` */DROP TABLE IF EXISTS `local_confirm_log`;CREATE TABLE `local_confirm_log` (  `tx_no` varchar(64) NOT NULL COMMENT '事務(wù)id',  `create_time` datetime DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `local_confirm_log` *//*Table structure for table `local_trade_log` */DROP TABLE IF EXISTS `local_trade_log`;CREATE TABLE `local_trade_log` (  `tx_no` bigint(20) NOT NULL,  `create_time` datetime DEFAULT NULL,  PRIMARY KEY (`tx_no`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;DROP TABLE IF EXISTS `local_try_log`;CREATE TABLE `local_try_log` (  `tx_no` varchar(64) NOT NULL COMMENT '事務(wù)id',  `create_time` datetime DEFAULT NULL,  PRIMARY KEY (`tx_no`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `local_try_log` *//*Table structure for table `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) NOT NULL,  `context` varchar(128) NOT NULL,  `rollback_info` longblob NOT NULL,  `log_status` int(11) NOT NULL,  `log_created` datetime NOT NULL,  `log_modified` datetime NOT NULL,  `ext` varchar(100) DEFAULT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.3.4.啟動(dòng)TC(事務(wù)協(xié)調(diào)器)

(1)下載seata服務(wù)器
下載地址 :seata服務(wù)器
(2)解壓并啟動(dòng)
winodws :【seata服務(wù)端解壓路徑】/bin/seata-server.bat -p 8888 -m file
mac/linux : 【seata服務(wù)端解壓路徑】nohup sh seata-server.sh -p 8888 -h 127.0.0.1 -m file &> seata.log &
注 :其中8888為服務(wù)端口號(hào);file為啟動(dòng)模式,這里指seata服務(wù)將采用文件的方式存儲(chǔ)信息。

在這里插入圖片描述

如上圖出現(xiàn)“Server started。。。“的字樣則表示啟動(dòng)成功。

3.3.5 discover-server

discover-server是服務(wù)注冊(cè)中心,測試工程將自己注冊(cè)至discover-server。

3.3.6 創(chuàng)建dtx-seata-demo

dtx-seata-demo是seata的測試工程,根據(jù)業(yè)務(wù)需求需要?jiǎng)?chuàng)建兩個(gè)dex-seata-demo工程。
(1)父工程maven依賴說明
在dtx父工程中指定了SpringBoot和SpringCloud版本


在這里插入圖片描述

在dtx-seata-demo父工程中指定了spring-cloud-alibaba-dependencies的版本。


在這里插入圖片描述

(3)配置seata
在src/main/resource中,新增registry.conf、file.conf文件,內(nèi)容可拷貝seata-server-0.7.1中的配置文件子。 在registry.conf中registry.type使用file:
在這里插入圖片描述

在file.conf中更改service.vgroup_mapping.[springcloud服務(wù)名]-fescar-service-group = "default",并修改 service.default.grouplist =[seata服務(wù)端地址]
在這里插入圖片描述

關(guān)于vgroup_mapping的配置:
vgroup_mapping.事務(wù)分組服務(wù)名=Seata Server集群名稱(默認(rèn)名稱為default) default.grouplist = Seata Server集群地址
在 org.springframework.cloud:spring-cloud-starter-alibaba-seata 的 org.springframework.cloud.alibaba.seata.GlobalTransactionAutoConfiguration 類中,默認(rèn)會(huì)使用 ${spring.application.name}-fescar-service-group 作為事務(wù)分組服務(wù)名注冊(cè)到 Seata Server上,如果和 file.conf 中的配置不一致,會(huì)提示 no available server to connect 錯(cuò)誤
也可以通過配置 spring.cloud.alibaba.seata.tx-service-group 修改后綴,但是必須和 file.conf 中的配置保持 一致。
(4)創(chuàng)建代理數(shù)據(jù)源
新增DatabaseConfiguration.java,Seata的RM通過DataSourceProxy才能在業(yè)務(wù)代碼的事務(wù)提交時(shí),通過這個(gè)切 入點(diǎn),與TC進(jìn)行通信交互、記錄undo_log等。

@Configurationpublic class DatabaseConfiguration {     @Bean    @ConfigurationProperties(prefix = "spring.datasource.ds0")     public  DruidDataSource ds0() {    DruidDataSource druidDataSource = new DruidDataSource();     return      druidDataSource;}    @Primary    @Bean    public DataSource dataSource(DruidDataSource ds0) {    DataSourceProxy pds0 = new DataSourceProxy(ds0);    return pds0;     }}

3.3.7 Seata執(zhí)行流程

1、正常提交流程


在這里插入圖片描述

2、回滾流程
回滾流程省略前的RM注冊(cè)過程。


在這里插入圖片描述

要點(diǎn)說明 :
1、每個(gè)RM使用DataSourceProxy連接數(shù)據(jù)庫,其目的是使用ConnectionProxy,使用數(shù)據(jù)源和數(shù)據(jù)連接代理的目的就是第一階段將undo_log和業(yè)務(wù)數(shù)據(jù)放在一個(gè)本地事務(wù)提交,這樣就保存了只要有業(yè)務(wù)操作就一定有undo_log.

2、在第一階段undo_log中存放了數(shù)據(jù)修改前和修改后的值,為事務(wù)回滾作好準(zhǔn)備,所以第一階段完成就已經(jīng)將分支事務(wù)提交,也就釋放了鎖資源。
3、TM開啟全局事務(wù)開始,將XID全局事務(wù)id放在事務(wù)上下午中,通過feign調(diào)用也將XID傳入下游分支事務(wù),每個(gè)分支事務(wù)將自己的Branch ID分支事務(wù)ID與XID關(guān)聯(lián)。
4、第二階段全局事務(wù)提交,TC會(huì)通知各個(gè)分支參與者提交分支事務(wù),在第一階段就已經(jīng)提交了分支事務(wù),這里各個(gè)參與者只需要?jiǎng)h除undo_log即可,并且可以異步執(zhí)行,第二階段很快可以完成。
5、第二階段全局事務(wù)回滾,TC會(huì)通知各個(gè)分支參與者回滾分支事務(wù),通過XID和Branch ID找到相應(yīng)的回滾日志,通過回滾日志生成反向的SQL并執(zhí)行,以完成分支事務(wù)回滾到之前的狀態(tài),如果回滾失敗則會(huì)重試回滾操作。

3.3.8 dtx-seata-demo-bank1

dtx-seata-demo-bank1實(shí)現(xiàn)如下功能:
1、張三賬戶減少金額,開啟全局事務(wù)。
2、遠(yuǎn)程調(diào)用bank2向李四轉(zhuǎn)賬。
(1)DAO

@Mapper@Componentpublic interface AccountInfoDao {    //更新賬戶金額@Update("update account_info set account_balance = account_balance + #{amount} where account_no = #{accountNo}")int updateAccountBalance(@Param("accountNo") String accountNo, @Param("amount") Double amount);}

(2) FeignClient
遠(yuǎn)程調(diào)用bank2的客戶端

 @FeignClient(value = "seata‐demo‐bank2",fallback = Bank2ClientFallback.class) public interface Bank2Client {@GetMapping("/bank2/transfer")String transfer(@RequestParam("amount") Double amount); }@Componentpublic class Bank2ClientFallback implements Bank2Client{@Overridepublic String transfer(Double amount) {return "fallback"; }}

(3)Service

@Servicepublic class AccountInfoServiceImpl implements AccountInfoService {private Logger logger = LoggerFactory.getLogger(AccountInfoServiceImpl.class);@AutowiredAccountInfoDao accountInfoDao;@AutowiredBank2Client bank2Client;//張三轉(zhuǎn)賬@Override@GlobalTransactional@Transactionalpublic void updateAccountBalance(String accountNo, Double amount) {    logger.info("******** Bank1 Service Begin ... xid: {}" , RootContext.getXID()); //張三扣減金額    accountInfoDao.updateAccountBalance(accountNo,amount*‐1);    //向李四轉(zhuǎn)賬    String remoteRst = bank2Client.transfer(amount); //遠(yuǎn)程調(diào)用失敗    if(remoteRst.equals("fallback")){    throw new RuntimeException("bank1 下游服務(wù)異常"); }    //人為制造錯(cuò)誤 if(amount==3){    throw new RuntimeException("bank1 make exception 3"); }    } }

將@GlobalTransactional注解標(biāo)注在全局事務(wù)發(fā)起的Service實(shí)現(xiàn)方法上,開啟全局事務(wù) :
GlobalTransactionalInterceptor會(huì)攔截@GlobalTransactional注解的方法,生成全局事務(wù)ID(XID),XID會(huì)在整個(gè)分布式事務(wù)中傳遞。
在遠(yuǎn)程調(diào)用時(shí),spring-cloud-alibaba-seata會(huì)攔截Feign調(diào)用將XID傳遞到下游服務(wù)。
(6)Controller

@RestControllerpublic class Bank1Controller {@AutowiredAccountInfoService accountInfoService;//轉(zhuǎn)賬@GetMapping("/transfer")public String transfer(Double amount){accountInfoService.updateAccountBalance("1",amount);return "bank1"+amount; }}

3.3.9 dtx-seata-demo-bank2

dtx-seata-demo-bank2實(shí)現(xiàn)如下功能:
1、李四賬戶增加金額。
dtx-seata-demo-bank2在本賬戶事務(wù)中作為分支事務(wù)不使用@GlobalTransactional。
(1)DAO

 @Mapper@Componentpublic interface AccountInfoDao {//向李四轉(zhuǎn)賬@Update("UPDATE account_info SET account_balance = account_balance + #{amount} WHERE account_no = #{accountNo}")int updateAccountBalance(@Param("accountNo") String accountNo, @Param("amount") Double amount);}

(2)Service

@Servicepublic class AccountInfoServiceImpl implements AccountInfoService {private Logger logger = LoggerFactory.getLogger(AccountInfoServiceImpl.class);@AutowiredAccountInfoDao accountInfoDao;@Override @Transactionalpublic void updateAccountBalance(String accountNo, Double amount) { logger.info("******** Bank2 Service Begin ... xid: {}" , RootContext.getXID()); //李四增加金額accountInfoDao.updateAccountBalance(accountNo,amount);//制造異常if(amount==2){throw new RuntimeException("bank1 make exception 2"); }} }

(3)Controller

 @RestControllerpublic class Bank2Controller {@AutowiredAccountInfoService accountInfoService;@GetMapping("/transfer")public String transfer(Double amount){accountInfoService.updateAccountBalance("2",amount);return "bank2"+amount; }}

3.3.10 測試場景

  • 張三向李四轉(zhuǎn)賬成功。

  • 李四事務(wù)失敗,張三事務(wù)回滾成功。

  • 張三事務(wù)失敗,李四事務(wù)回滾成功。

  • 分支事務(wù)超時(shí)測試。

3.4. 小結(jié)

傳統(tǒng)2PC(基于數(shù)據(jù)庫XA協(xié)議)和Seata實(shí)現(xiàn)2PC的兩種2PC方案,由于Seata的零入侵并且解決了傳統(tǒng)2PC長期鎖資源的問題,所以推薦采用Seata實(shí)現(xiàn)2PC。
Seata實(shí)現(xiàn)2PC要點(diǎn) :
1、全局事務(wù)開始使用GlobalTransactional標(biāo)識(shí)。
2、每個(gè)本地事務(wù)方案仍然使用@Transactional標(biāo)識(shí)。
3、每個(gè)數(shù)據(jù)都需要?jiǎng)?chuàng)建undo_log表,此表是Seata保證本地事務(wù)一致性的關(guān)鍵。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
分布式事務(wù)解決方案之2PC(二)
分布式事務(wù)有這一篇就夠了
《我想進(jìn)大廠》之分布式事務(wù)篇
你對(duì)seata框架有所了解嗎?知道如何使用嗎?
如何選擇分布式事務(wù)解決方案?
分布式事務(wù)( 圖解 + 秒懂 + 史上最全 )
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服