前言
上一篇文章:➣SpringCloud Alibaba之Seata入門以及踩坑(一)老顧介紹了seata相關的準備工作,以及版本的選擇;今天老顧就來介紹一下seata的使用。以及在使用過程中遇到的問題。
案例背景
今天老顧介紹的案例場景也就是網上常用的場景,用戶下單場景。整個流程就是用戶下單時:
1)創建訂單,訂單狀態爲創建中
2)扣減商品庫存
3)扣減用戶金額
4)更改訂單狀態,訂單狀態爲已完結
從以上業務流程,我們可以分爲3個服務,如圖
因爲上面是3個分佈式服務,事務問題就由此產生,我們來看看seata怎麼來解決?
Client端準備
上文中已經介紹了seata-server的準備工作,需要首先啓動seata服務。下面我們來看看client端項目需要做什麼準備。
項目依賴
我們需要在項目中引入seata的jar包,有以下選擇(任選其一):
- 依賴seata-all 手動配置較多
- 依賴seata-spring-boot-starter,支持yml配置
- 依賴spring-cloud-starter-alibaba-seata,內部集成了seata,並實現了xid傳遞
注意:client 版本與 server端版本一致
上面三種方式,需要做不同的事情,尤其xid的傳遞是比較麻煩的,還好spring-cloud-starter-alibaba-seata已經幫我們實現,具體看看下圖:
這裏我們就用spring-cloud-starter-alibaba-seata方式。
因爲我們seata-server用了1.3.0,所以我們client也需要同一版本。
數據庫準備
3個微服務rb-order-server、rb-account-server、rb-storage-server我們就創建3個數據庫。
seata-order庫中創建t_order
seata-account庫中創建t_account
seata_storage庫中創建t_storage
項目新建undo_log表
每個微服務項目有獨立的數據庫,則需要在庫中創建undo_log表
微服務項目中引入mybatis-plus操作數據庫,這裏老顧就不介紹了。
微服務配置
我們聚焦到seata相關上面;上文中我們seata-server服務是結合nacos的。
我們在rb-order-server、rb-account-server、rb-storage-server3個服務的application.yml配置文件中,都要配置相關seata的配置。
上面的配置比較容易理解,有幾個地方很重要:
1)enable-auto-data-source-proxy
這個配置就是啓動自動開啓數據源代理。
2)tx-service-group:seata_test_tx_group
這個是事務分組,項目的微服務都要配置一樣的事務分組,並且要和上文中的seata-server的service.vgroupMapping.seata_test_tx_group=default一致。
數據庫代理
因爲seata採用了DataSource代理方式操作數據,所以在springboot項目中先要排除datasource初始化,這樣yml文件中的seata.enable-auto-data-source-proxy: true 自動代理纔會生效。如何排除也是比較簡單,三個服務都要排除,啓動自動數據庫代理。
以上client準備工作就結束了。
Feign調用
因爲order服務中要調用account服務、storage服務,所以order中需要引入feign調用,如果把三個服務加入註冊中心,能夠互動調用;老顧這裏就不介紹了,小夥伴們可以看老顧的以前的文章。
我們在來看看各個服務的具體實現。
項目服務代碼
庫存服務
上面的代碼,能夠發現如果下單的時候超過庫存數,就會拋異常;
用戶服務
上面的代碼,如果扣減的金額超過用戶金額時,就拋異常;
訂單服務
上面的訂單服務代碼中,我們發現引入了@GlobalTransactional;對的,就是加入了@GlobalTransactional這個註解,就實現了分佈式事務,簡單吧。
我們可以啓動postman,請求count參數爲1的話,查看業務數據庫數據都正常。對應的庫存減少了1,金額減少了100,訂單成功插入。
如果我們傳入的count參數大於庫存數,庫存服務就會拋異常,那庫存服務就會執行失敗,這樣訂單服務,用戶服務也會回滾。這樣就起到了分佈式事務作用。
感覺到這裏,小夥伴們是不是感覺seata的強大,這個就是seata推薦的AT模式。
Feign降級坑
在我們微服務使用中,一旦微服務產生異常,我們都會用到降級的功能;如在調用庫存服務的時候引入sentinel降級,這個知識老顧之前就介紹過,小夥伴們可以查看之前的文章。
spring:
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
feign:
sentinel:
enabled: true
這樣對庫存服務的降級處理是實現了,這也是正常的微服務的使用。
但是這樣的處理,seata就會失效;我們發現count參數大於庫存時,庫存服務報異常,但因爲有降級處理,訂單還是提交了訂單數據,用戶金額還是減少了。事務不起作用了。
解決方式
官方推薦的方法,就是利用aop方式,手動處理全局事務回滾,我們在庫存服務中加入aop
從上述代碼中,我們用容易發現,如果執行的service中出現異常,就手動實現全局事務rollback。這樣就解決了Feign的降級的問題。
注意:上面的aop代碼中,before、after方法中,可以結合自身的業務 本案例中庫存服務,只在拋異常的時候做了處理
總結
seata的分佈式事務使用起來是非常簡單的,但是seata的使用會對現有項目中產生一些意外的錯誤,但是都可以得到相應的解決;需要小夥伴去實踐。謝謝!!!