一、使用場景 :
1.功能實現(xiàn)需多次進行數(shù)據(jù)庫操作
2.方法中包含請求第三方API接口
二罢猪、第三方API使用遇到的場景
(1) 第三方API成功或失敗不影響主體業(yè)務的進行,如消息推送
處理方法: 把消息推送的方法摘出來,進行異步處理生百,避免請求出錯影響主體業(yè)務流程孙蒙;
注意 : 需把異步方法抽取到另一個類中项棠,否則@Async不生效
(2) 第三方API與主體業(yè)務不可分割(如員工調(diào)動,員工離職相關API)
處理展示 :
① 請求API挎峦,根據(jù)API返回結(jié)果進行業(yè)務處理(進行數(shù)據(jù)庫操作)
② 先進行數(shù)據(jù)庫操作香追,再請求第三方的API
思考:①和②兩種處理方式的區(qū)別?
① 請求API坦胶,根據(jù)API返回結(jié)果進行業(yè)務處理(進行數(shù)據(jù)庫操作)
問題 : 如果API接口返回錯誤透典,則無需往下執(zhí)行后續(xù)業(yè)務邏輯處理晴楔,直接終止
但是,如果API請求通過峭咒, 后續(xù)業(yè)務邏輯執(zhí)行一旦出錯税弃,進行回滾, API無法回滾 凑队, 導致事務不一致
例如員工離職则果,已從釘釘架構中移除員工,但是數(shù)據(jù)庫狀態(tài)回滾為正常狀態(tài)漩氨,造成數(shù)據(jù)不一致
② 先進行數(shù)據(jù)庫操作西壮,再請求第三方的API
優(yōu)點:請求第三方API發(fā)生錯誤時,可以回滾數(shù)據(jù)庫數(shù)據(jù)叫惊;
可以得出結(jié)論第①種順序(先API,后修改庫)是有致命缺陷的款青,這種處理方式在代碼里禁止使用!
二丶遇到API如何應該如何做霍狰?
1抡草、API請求共性
(1)、明確成功
明確成功的意思很明顯蔗坯,這也是我們最常用到的成功情況康震,當?shù)谌浇o你返回200狀態(tài)碼或OK時,就可以是明確成功了步悠。
可能存在的問題:請求時間過長
(2)签杈、明確失敗
明確成功的意思很明顯,這也是我們最常用到的失敗情況鼎兽,當?shù)谌浇o你返回非200狀態(tài)碼或OK時答姥,就可以是明確失敗了,你就可以處理回滾了谚咬。
可能存在的問題:請求時間過長
(3)鹦付、結(jié)果未知
當你請求發(fā)過去了,因為第三方處理時間過長(可能是他們服務器有問題择卦,也可能是業(yè)務復雜)敲长,導致連接直接斷開了,誰也不知道他那邊是否處理完成了秉继。
可能存在的問題:超時情況
2祈噪、API請求存在的問題
(1)、API請求超時無法處理
請求API超時尚辑,程序判定修改失敗辑鲤,事務回滾, 但是API方法實際還在執(zhí)行杠茬,導致數(shù)據(jù)不一致月褥。
(2)弛随、API請求時間過長,長時間占用庫問題
雖然API請求成功了宁赤,但是20s才處理完成舀透,因為在上面我們對自己庫的操作已經(jīng)在事務里面了,還未提交决左,所以將導致我們的操作被鎖定20s愕够,當堆積的多了,就會產(chǎn)生問題哆窿。
3链烈、解決方案:
方案1: 解決超時問題
如果有條件- 調(diào)用方和被調(diào)用方協(xié)調(diào)好,可以為調(diào)用方提供回調(diào)或輪詢查詢接口
回調(diào):比如超級店長調(diào)用千云挚躯,千云給超級店長提供一個回調(diào)接口,返回處理結(jié)果
輪詢:超級店長定時去請求千云擦秽,獲取結(jié)果
這樣做的好處码荔?
通過被調(diào)用方提供的回調(diào)或輪詢功能,我們能夠明確的知道自己調(diào)用是否完全成功或完全失敗感挥,不會存在模棱兩個的情況缩搅。保證了第三方API結(jié)果的確定性,為事務的一致性構建了前提触幼。
這樣做的缺點
這樣做沒有缺點硼瓣,正規(guī)的程序都會提供,唯一的缺點就是不正規(guī)的可能不提供置谦,這也就要求我們在為別人提供業(yè)務接口的時候堂鲤,要根據(jù)業(yè)務的重要程度,為他人提供回調(diào)或輪詢方法媒峡。
方案2:解決庫占用問題
啟用編程式事務瘟栖,包裹住對數(shù)據(jù)庫修改的操作
// 方法上不加事務
public SimpleMessage testA() {
// 進行校驗參數(shù),一些查詢
Select ***
// 開啟事務谅阿,進行一些數(shù)據(jù)庫修改操作
transactionTemplate.execute(status -> {
update ***
update ***
return null;
});
// 進行第三方API請求
httpUtils.post***;
return new SimpleMessage(ErrorCodeEnum.OK);
}
這樣做的好處半哟?
自己庫的多個操作數(shù)據(jù)已經(jīng)執(zhí)行完成,事務也已經(jīng)提交釋放签餐,且api請求不在事務中寓涨,自己的庫不會被鎖。
這樣做的缺點
雖然庫不被占用了氯檐,但是第三方請求如果失敗了戒良,事務仍然會不一致。而且還是無法解決超時問題男摧,有可能存在超時情況蔬墩,結(jié)果未知導致事務不一致译打。
方案3:在①和②的基礎上改進
在方案②的基礎上對失敗的情況恢復處理(使用編程式事務)
在方案①的基礎上使用 回調(diào)/輪詢處理
// 方法上不加事務
public SimpleMessage testA() {
// 進行校驗參數(shù),一些查詢
Select ***
// 開啟事務拇颅,進行一些數(shù)據(jù)庫修改操作
transactionTemplate.execute(status -> {
update num = 2 where ***
update ***
return null;
});
// 進行第三方API請求
httpUtils.post***
// 根據(jù)API請求返回結(jié)果奏司, 如果失敗則對數(shù)據(jù)進行回退操作
// 開啟事務,進行數(shù)據(jù)恢復操作
transactionTemplate.execute(status -> {
update num = 1 where ***
update ***
return null;
});
return new SimpleMessage(ErrorCodeEnum.OK);
}
提示
TransactionTemplate執(zhí)行時樟插,不論發(fā)生受檢查的異常(Exception)韵洋,還是不受檢查的異常(RuntimeException),都會執(zhí)行回滾操作黄锤,所以無需擔心事務不提交問題導致的重大bug搪缨。
這樣做的好處
1、防止了庫被占用鸵熟,且得到失敗的結(jié)果后能進行手動回滾副编。
這樣做的缺點
1.寫起來比較麻煩
2.如果第三方不提供回調(diào)或輪詢,還是沒辦法保證事務一致性流强,所以第三方很重要痹届。如果第三方提供,搭配①方案使用打月,就是完美解決方案队腐,如果第三方不提供,將不存在完美解決方案奏篙,也間接說明這個業(yè)務不是很重要且開發(fā)人員很拉跨柴淘。