SpringBoot集成Seata的全過程
1.本地事務和分布式事務概念
事務四大特性
- 原子性:事務不可再分
- 一致性:數(shù)據(jù)改變前后,總量必須一致
- 隔離性:事務之間相互隔離,互不干擾
- 持久性:事務一旦提交,數(shù)據(jù)就會持久化到磁盤,不能回滾
本地事務:所有的事務都是基于數(shù)據(jù)庫的,那么我們在代碼中加@Transactional其實是使用的數(shù)據(jù)庫的Begin/Commit/Rollback,底層使用的是動態(tài)代理。本地事務只能管理到當前服務連接的那個數(shù)據(jù)庫的事務,如果一個事務中操作了多個數(shù)據(jù)庫在回顧的時候只能回滾當前服務連接的那個數(shù)據(jù)庫,沒辦法回滾其它數(shù)據(jù)庫
分布式事務:用于解決在一個方法中操作多個數(shù)據(jù)庫的事務,分布式事務其實就是將多個數(shù)據(jù)庫加入到同一組事務中,當某一個數(shù)據(jù)庫發(fā)生異常時整體回滾
2.分布式事務的解決方案
2.1 XA協(xié)議
- 簡單理解就是XA規(guī)范協(xié)議是一種事務協(xié)議,通過這種協(xié)議來通知數(shù)據(jù)庫事務的開始、結(jié)束、提交、以及回滾,XA 接口函數(shù)由數(shù)據(jù)庫廠商提供。XA協(xié)議使用二階段提交來處理分布式事務,說的更明白一點就是XA協(xié)議保證了分布式事務的原子性,要么都成功,要么都失敗。
- XA協(xié)議采用兩階段提交方式來管理分布式事務
2.2 2PC模式
2PC就是基于XA協(xié)議進行實現(xiàn)的,采用兩階段提交 2PC(Two Phase Commitment Protocol)來管理分布式事務,所謂二階段是有兩個階段組成,一階段投票階段和二階段提交階段。同時它是由“事務協(xié)調(diào)器”和若干“事務執(zhí)行者”兩個角色組成。
第一階段:準備階段( 投票階段 )

- 事務協(xié)調(diào)器向所有事務參與者發(fā)請求,詢問是否可以執(zhí)行提交操作(你們都可以執(zhí)行事務操作嗎?),并開始等待各參與者節(jié)點的響應。
- 事務參與者收到協(xié)調(diào)者的指令開始執(zhí)行事務操作但是不會提交事務,同時寫Undo log(寫操作之前首先將數(shù)據(jù)備份log,如果要回滾就從這個log進行數(shù)據(jù)還原) 和 Redo log(修改數(shù)據(jù)在buffer pool緩沖池中修改,Redo log是對這個緩沖池的內(nèi)容做持久,避免修改的數(shù)據(jù)丟失) 。
- 如果參與者事務操作都執(zhí)行成功(注意哦,沒提交事務哦),那么就會回復 事務協(xié)調(diào)器 “準備OK” ,如果事務操作失敗,那么就會回復執(zhí)行者“準備不OK”。
第二階段:提交階段

正常流程
- 事務協(xié)調(diào)器會收到參與者的回復,如果所有的參與者都回復“準備ok”,意味著所有的參與者都可以完成事務操作,那么事務協(xié)調(diào)器會向每個事務參與者發(fā)送一個“commit” 提交事務指令(既然大家都可以進行事務操作,那大家都提交事務把)
- 事務參與者收到指令就開始提交事務,然后會向事務協(xié)調(diào)器回復“完成”,事務協(xié)調(diào)器收到所有參與者都回復完成,事務完成

回滾流程
- 如果再第一階段事務協(xié)調(diào)器收到了某個事務參與者回復“準備不ok”即事務操作執(zhí)行失敗,那么事務協(xié)調(diào)器會向所有的事務參與者發(fā)送“rollback”回滾執(zhí)行(有一個成員不ok,那大家都散了吧,今天的事情搞不成了)
- 事務參與者收到指令,回滾之前的事務操作,即:將數(shù)據(jù)還原到“Undo log”的數(shù)據(jù),然后向事務協(xié)調(diào)者回復“回滾成功”,當事務協(xié)調(diào)器收到所有的參與者回復“回滾成功”后,取消事務。
發(fā)送回滾指令

二階段提交的問題
- 二階段能保證分布式事務的原子性,但是也有一些明顯的缺陷。比如:在第一階段,如果參與者遲遲不回復協(xié)調(diào)者,就會造成事務的阻塞,性能不好。
- 單節(jié)點故障,如果協(xié)調(diào)器掛了,參與者會阻塞,比如在第二階段,如果事務協(xié)調(diào)器宕機,參與者沒辦法回復信息,長時間處于事務資源鎖定,造成阻塞(事務操作是要加鎖的)。
- 在第二階段,如果在事務協(xié)調(diào)器發(fā)出"commit"執(zhí)行后宕機,一部和參與者收到了消息提交了事務,而一部分沒有消息沒法做出事務提交操作,這樣就出現(xiàn)了數(shù)據(jù)不一致。
- 在第二階段,如果事務事務協(xié)調(diào)器發(fā)出“commit”指令后宕機,收到“commmit”指令的參與者也宕機了,那么事務最終變成了什么效果,提交了還是沒提交?沒有誰知道。
2.3 3PC模式
三階段提交(Three-phase commit),也叫三階段提交協(xié)議(Three-phase commit protocol),是二階段提交(2PC)的改進版本,
3PC在2PC的功能上做了兩個改動,一是在協(xié)調(diào)者和事務參與者之間引入了超時機制,在第一階段和第二階段中插入一個準備階段 , 保證了在最后提交階段之前各參與節(jié)點的狀態(tài)是一致的,那么現(xiàn)在的三階段分為了:
- canCommit“詢問是否能提交,
- papreCommit”準備提交階段 ,
- doCommit”提交階段。

第一階段“canCommit” :
- 事務協(xié)調(diào)者向事務參與者發(fā)送 canCommit 請求詢問是否能提交事務,然后等待所有事務參與者的返回
- 事務參與者接收到事務些調(diào)整的canCommit指令,然后自身認為能夠提交事務則返回 “yes”否則返回“no”
第二階段“papreCommit”
事務協(xié)調(diào)者收到所有的事務參與者的canCmmit指令的反饋結(jié)果,這里有兩種情況,一是所有的反饋都是yes,二是有部分的事 務參與者返回No,后者反饋超時。
正常流程
- 如果事務協(xié)調(diào)者收到所有的事務參與者的canCmmit指令反饋結(jié)果都為YES,那么就進入papreCommit階段。事務協(xié)調(diào)者向事務參與者發(fā)送 “papreCommit”指令。
- 事務參與者收到“papreCommit”指令,開始進行事務操作,并將undo和redo信息記錄到事務日志中,如果順利執(zhí)行事務操作,則反饋ACK確認信息,然后等待下一步指令。
中斷事務
- 如果事務協(xié)調(diào)者收到所有的事務參與者的canCmmit指令反饋結(jié)果出現(xiàn)了NO,或者等待超時,那么就執(zhí)行事務中斷,向所有的事務參與者發(fā)送“abort”中斷指令。
- 事務參與者接收到“abort”指令,中斷事務,當然如果事務參與者遲遲未收到事務協(xié)調(diào)者的指令等待超時也會中斷事務。
第三階段“doCommit階段”
這里準備提交事務了,這里有兩種情況,如果事務協(xié)調(diào)者收到所有的事務參與者的papreCommit指令反饋結(jié)果都是ACK,那么進入doCommit階段,否則會中斷事務。
正常流程
- 事務協(xié)調(diào)者收到所有的事務參與者的papreCommit指令反饋結(jié)果都是ACK,然后向事務參與者發(fā)送“doCommit”指令,通知提交事務。
- 事務參與者收到“doCommit”指令,正式執(zhí)行事務提交,并且釋放所有事務資源,返回向事務協(xié)調(diào)者返回事務結(jié)果狀態(tài)“ACK”完成
- 事務協(xié)調(diào)者收到所有的事務參與者都返回ACK成功,完成事務。
中斷事務
- 事務協(xié)調(diào)者收到的事務參與者的papreCommit指令反饋結(jié)果有的不是ACK,那么事務協(xié)調(diào)者然后向事務參與者發(fā)送“abort”事務中斷指密令。
- 事務參與者收到“abort”事務指令,會根據(jù)unlog日志文件還原數(shù)據(jù),然后釋放事務資源,然后向事務協(xié)調(diào)者發(fā)送回滾“ACK”消息
- 事務協(xié)調(diào)者收到所有的事務參與者都返回ACK消息,取消事務。
2.4 TCC事物補償

TCC(Try Confirm Cancel) 事務補償機制,即每一個操作都要做相應的補償機制,即如何確認操作成功,如果操作失敗如何撤銷事務。它分為三個階段
- Try : try的意思是嘗試,其實這個步驟是用來做業(yè)務的預處理,可以理解為是做一些準備工作,等到Confirm之后這些操作才算成功。
- Confirm :確認,如果所有的事務參與者都try成功,執(zhí)行commit對業(yè)務做提交操作,或者可以理解成對try的工作作出確認。
- Cancel:取消,如果try失敗需要回滾,即取消try的預處理操作
2.5 MQ消息最終一致性

大致流程是:
1.主業(yè)務方向發(fā)送一個“Prepared”準備消息到MQ,這個消息還未被確認,不會發(fā)生給消費者,然后MQ向生產(chǎn)者發(fā)送確認收到消息,然后主業(yè)務方執(zhí)行自己的業(yè)務,并提交本地事務,成功后向MQ確認之前的“Prepared”消息發(fā)生給消費者,如果失敗MQ將當前半消息刪除,取消事務。
2.消息接受者方收到消息后執(zhí)行業(yè)務邏輯,提交本地事務,然后向MQ返回ACK確認消息,如果ACK消息為成功,MQ則刪除當前消息;如果消費者消息接受失敗或返回ACK是失敗,會進行重試,保證消息最終被消費。直到16次后還是失敗,消息會進入死信隊列,該消息不會被刪除,也不會重發(fā),需要人工介入;

RocketMQ的事務消息:使用MQ的分布式事務是最終一致性
- 生成者發(fā)送一個半事務消息給MQ,MQ告訴生產(chǎn)者接收到了,此時生產(chǎn)者方就去執(zhí)行本地事務
- 如果執(zhí)行成功那么告訴MQ執(zhí)行Commit,如果本地事務失敗MQ執(zhí)行Rollback。那么MQ執(zhí)行Commit就是把此消息發(fā)送給消費者,消費者接收到消息之后執(zhí)行本地事務,如果執(zhí)行成功那么響應ACK確認成功,如果執(zhí)行失敗那么響應ACK失敗,MQ接收到成功刪除此消息,如果失敗那么會再次發(fā)送,直到16次之后還是失敗那么進入到死信隊列,此時就需要我們?nèi)斯とz查代碼手動發(fā)送消息再次消費。如果MQ執(zhí)行Rollback那么就會把此消息進行刪除。
- 如果避免生產(chǎn)者一直不提交commit或rollback還準備了一個回查機制,調(diào)用我們寫的一個方法,在方法中去檢查生產(chǎn)者的本地事務是否執(zhí)行成功,如果成功提交commit,如果失敗提交rollback
2.6 Seata框架
seata(Simple Extensible Autonomous Transaction Architecture) 是 阿里巴巴開源的分布式事務中間件,致力于提供高性能,零入侵和簡單易用的分布式事務服務。Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務模式,為用戶打造一站式的分布式解決方案。
Seata 的設(shè)計思路是將一個分布式事務可以理解成一個全局事務,下面掛了若干個分支事務,而一個分支事務是一個滿足 ACID 的本地事務,因此我們可以操作分布式事務像操作本地事務一樣。
Seata重要組成
- Transcation ID(XID) : 由事務協(xié)調(diào)者創(chuàng)建的全局唯一的事務ID
- Transaction Coordinator(TC) - 事務協(xié)調(diào)器:一個獨立運行的組件,負責維護全局事務的運行狀態(tài),負責根據(jù)TM的指令協(xié)調(diào)并驅(qū)動全局事務的提交或回滾,負責向資源管理器發(fā)起事務提交,回滾指令。
- Transaction Manager - 事務管理器 :控制全局事務的邊界,負責開啟一個全局事務,并最終發(fā)起全局提交或全局回滾的決議,通知TC提交或者回滾事務。
- Resource Manager(RM) - 資源管理器: 控制分支事務,負責分支事務注冊、負責向TC匯報分支事務狀態(tài),并接收事務協(xié)調(diào)器的指令,驅(qū)動分支(本地)事務的提交和回滾

正常執(zhí)行流程:
- 系統(tǒng)啟動TM事務管理者以及RM資源管理者需要向事務協(xié)調(diào)器進行提交注冊,可以看做是一種初始化。
- 在Bussiness的業(yè)務主方法上我們需要打上@GlobalTransationl注解,通過這個注解,事務管理器TM向事務協(xié)調(diào)者(TC)申請開啟一個全局分布式事務,事務協(xié)調(diào)者創(chuàng)建全局事務后返回全局唯一的 XID,這個XID 會在涉及微服務的整個全局事務的上下文中進行傳播。
- 業(yè)務開始,Bussiness通過Feign調(diào)用Order,并傳遞全局事務XID,Order在做寫操作的時候,RM資源管理器 (Order集成了RM)向事務 協(xié)調(diào)器TC 注冊本地分支事務,該分支事務歸屬于擁有相同 XID 的全局事務,同時事務協(xié)調(diào)者TC會返回一個分支事務ID:“branchId” 。說明一下:Seate通過代理DataSource向TC發(fā)起分子事務注冊的。
- 這個時候Order會正常的寫數(shù)據(jù)庫,然后會寫入一個undo log(這個日志文件記錄了數(shù)據(jù)庫修改前的數(shù)據(jù),用來做回滾),然后提交分支事務(注意,分支事務已經(jīng)提交了) , 最后向TC上報事務處理狀態(tài)。當然Account做的事情和Order是相同的。
- Order和Account都調(diào)用完成,代碼回到Business,這時TM事務管理器向TC事務協(xié)調(diào)者發(fā)起全局事務提交請求,TC向RM事務分支發(fā)起事務提交請求,RM(Order, Account)直接刪除到undo log日志文件即可,因為之前已經(jīng)提交了本地事務

異常執(zhí)行流程:
前面2個步驟都跟上面一樣,這里省略 , 在第 3 步的時候,Order在可能因為某種原因本地分支事務提交失敗了,那么RM會向TC上報一個失敗的事務狀態(tài)
在第 4 步 ,這個時候代碼回到Business,這時TM事務管理器會向TC事務協(xié)調(diào)者發(fā)起全局事務回滾請求,TC向RM事務分支發(fā)起事務回滾請求,RM(Order, Account)收到回滾指令,然后會解析undo log,指向反向操作,把數(shù)據(jù)還原到修改之前,刪除undo log,提交本地事務。
3.微服務整合seata
3.1導入依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>3.2yaml配置seata
項目的yaml中對seata做配置
這里的tx-service-group: ${spring.application.name}-tx-group要和seataServer.properties中的保持一致
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-tx-group #it-fccar-service-driver-tx-group
#對應seataServer.properties中的service.vgroupMapping.it-drive-service-driver-tx-group=default
config:
type: nacos
nacos:
server-addr: ${NACOS_HOST:8.137.85.173:8848}:${NACOS_PORT:8848}
username: nacos
password: nacos #賬號再nacos管理界面配置
namespace: fccar-dev #取pom.xml中的命名空間
data-id: seataServer.properties
group: DEFAULT_GROUP #重要,和seataServer.properties保持一樣
registry:
type: nacos
nacos:
application: service-seata #seata的服務名
server-addr: ${NACOS_HOST:8.137.85.173:8848}:${NACOS_PORT:8848}
username: nacos
password: nacos #賬號再nacos管理界面配置
namespace: fccar-dev #取pom.xml中的命名空間
group: DEFAULT_GROUP
enable-auto-data-source-proxy: true #開啟seata的datasource自動代理在啟動類貼注解開啟seata , 因為yaml做了配置,下面注解可以不要
@EnableAutoDataSourceProxy(dataSourceProxyMode="AT",useJdkProxy=false)
3.3.開啟全局事務
開啟全局事務,在入口方法貼注解
注意:只在業(yè)務入口的微服務的方法上貼即可
@GlobalTransactional(name = "driver-wechat-register",rollbackFor = Exception.class)
到此這篇關(guān)于SpringBoot集成Seata的文章就介紹到這了,更多相關(guān)SpringBoot集成Seata內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解SpringBoot之訪問靜態(tài)資源(webapp...)
這篇文章主要介紹了詳解SpringBoot之訪問靜態(tài)資源(webapp...),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09
關(guān)于idea的gitignore文件編寫及解決ignore文件不生效問題
這篇文章主要介紹了idea的gitignore文件編寫及解決ignore文件不生效問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03
spring mvc中直接注入的HttpServletRequst安全嗎
這篇文章主要給大家介紹了關(guān)于spring mvc中直接注入的HttpServletRequst是不是安全的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧。2018-04-04
java基于QuartzJobBean實現(xiàn)定時功能的示例代碼
QuartzJobBean是Quartz框架中的一個抽象類,用于定義和實現(xiàn)可由Quartz調(diào)度的作業(yè),本文主要介紹了java基于QuartzJobBean實現(xiàn)定時功能的示例代碼,具有一定的參考價值,感興趣可以了解一下2023-09-09
解讀@ResponseBody與@RequestBody注解的用法
這篇文章主要介紹了Spring MVC中的@ResponseBody和@RequestBody注解的用法,@ResponseBody注解用于將Controller方法的返回對象轉(zhuǎn)換為指定格式(如JSON)并通過Response響應給客戶端,@RequestBody注解用于讀取HTTP請求的內(nèi)容2024-11-11
Java面試Socket編程常用參數(shù)設(shè)置源碼問題分析
這篇文章主要為大家介紹了Java編程中關(guān)于Socket結(jié)構(gòu)分析,常用參數(shù)設(shè)置源碼示例以及面試中的問題分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-03-03

