您好,登錄后才能下訂單哦!
Springcloud中的分布式事務怎么利用seata實現?相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
Seata 是一款開源的分布式事務解決方案,致力于提供高性能和簡單易用的分布式事務服務。
大致上seata分為TC,TM,RM三大構建成整體。它們之間的包含關系如下。即一(xid主鍵編碼,記錄信息)帶三(TC,TM,RM)
下面之間構建項目進行測試。
1.下載seata并解壓,然后改動配置文件。
http://seata.io/zh-cn/blog/download.html官網下載。
解壓之后到conf中修改file和registry文件,修改之前一定記得先備份。
file.conf,改動兩個地方
將group后面的參數定義一個名字,隨意
存儲方式選db放在數據庫,自然其配置信息根據自己的數據庫去填寫。
然后是register文件,填寫信息將seata注冊到nacos中。
啟動自然是在bin中打開bat文件即可,注意需要先啟動naco。
2.構建項目(order,storage,account)
演示整體的服務調用還有服務報錯的時候進入回滾。通過創建訂單->檢查庫存并扣除->檢查賬戶并扣除->修改訂單狀態
具體代碼可查看GitHub
https://github.com/MaTsukun/springcloud2020
關鍵的service方法
@Service @Slf4j public class OrderServiceImpl implements OrderService{ @Resource private OrderMapper orderMapper; @Resource private StorageService storageService; @Resource private AccountService accountService; @Override @GlobalTransactional(name="abc-create-order",rollbackFor = Exception.class) public void create(Order order){ //1.創建訂單 log.info("開始創建訂單"); orderMapper.create(order); //2.減少庫存 log.info("查詢庫存并且進行更改"); storageService.decrease(order.getProductId(),order.getCount()); //3.扣除費用 log.info("查詢余額并扣除費用"); accountService.updateAccount(order.getUserId(),order.getMoney()); //4.修改狀態 log.info("更改訂單狀態"); orderMapper.update(order.getUserId(),0); log.info("訂單結束,O(∩_∩)O哈哈~"); } }
可以看到在order項目中同時調用了storage和account的項目的方法,采用的是openfeign,整體形成了一個鏈路,成為一個整的事務。
而添加的GlobalTransactional注解則保證了事務中任何一方出現錯誤就會使整個項目的執行過程進行回滾,而不是單事務的回滾。
3.seata回滾原理
在每次注解的方法里進行執行sql語句的時候都會創建一個id記錄此次的寫操作同時在每次的寫操作前后都會生成前置記錄和后置記錄,可以在出現錯誤回滾的時候,通過記錄進行逆操作回滾重新將數據寫回去。
通過數據庫配置的seata庫展示可以看見對應的記錄id信息,通過debug模式暫停服務,查看記錄的信息。
global的全局xid
account表的undo記錄
記錄的信息json格式
{ "@class": "io.seata.rm.datasource.undo.BranchUndoLog", "xid": "192.168.2.141:8091:2060193863", "branchId": 2060193875, "sqlUndoLogs": [ "java.util.ArrayList", [ { "@class": "io.seata.rm.datasource.undo.SQLUndoLog", "sqlType": "UPDATE", "tableName": "t_account", "beforeImage": { "@class": "io.seata.rm.datasource.sql.struct.TableRecords", "tableName": "t_account", "rows": [ "java.util.ArrayList", [ { "@class": "io.seata.rm.datasource.sql.struct.Row", "fields": [ "java.util.ArrayList", [ { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "id", "keyType": "PrimaryKey", "type": -5, "value": [ "java.lang.Long", 1 ] }, { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "used", "keyType": "NULL", "type": 3, "value": [ "java.math.BigDecimal", 600 ] }, { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "residue", "keyType": "NULL", "type": 3, "value": [ "java.math.BigDecimal", 400 ] } ] ] } ] ] }, "afterImage": { "@class": "io.seata.rm.datasource.sql.struct.TableRecords", "tableName": "t_account", "rows": [ "java.util.ArrayList", [ { "@class": "io.seata.rm.datasource.sql.struct.Row", "fields": [ "java.util.ArrayList", [ { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "id", "keyType": "PrimaryKey", "type": -5, "value": [ "java.lang.Long", 1 ] }, { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "used", "keyType": "NULL", "type": 3, "value": [ "java.math.BigDecimal", 700 ] }, { "@class": "io.seata.rm.datasource.sql.struct.Field", "name": "residue", "keyType": "NULL", "type": 3, "value": [ "java.math.BigDecimal", 300 ] } ] ] } ] ] } } ] ] }
可以看到里面有beforeimage和afterimage快照記錄,通過這些記錄可以實現逆操作,重新寫進數據實現回滾。
看完上述內容,你們掌握Springcloud中的分布式事務怎么利用seata實現的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。