在業(yè)務(wù)處理中,我們有時(shí)候會碰到一些場景,他們需要執(zhí)行多個(gè)步驟才能算完成,然而這幾個(gè)步驟并非是連續(xù)立即執(zhí)行的。
舉一個(gè)例子,在處理訂單業(yè)務(wù)的時(shí)候,我們接收到訂單,需要將訂單保存到數(shù)據(jù)庫中,然后,要將其存入Redis緩存,完了還要將其轉(zhuǎn)發(fā)給其他相關(guān)系統(tǒng)。轉(zhuǎn)發(fā)其他系統(tǒng)的過程也是成對的操作,需要將轉(zhuǎn)發(fā)的數(shù)據(jù)存入一份處理表同時(shí)向消息隊(duì)列中也傳一份,根據(jù)發(fā)送到對方系統(tǒng)中的反饋消息進(jìn)行相應(yīng)處理(處理成功則將處理表中對應(yīng)數(shù)據(jù)刪除,處理失敗則對該數(shù)據(jù)進(jìn)行重新發(fā)送,或者根據(jù)業(yè)務(wù)需求重新操作)。
這樣的業(yè)務(wù),會有幾個(gè)顯而易見的問題。
問題一、保存數(shù)據(jù)庫的操作需要事務(wù),但事務(wù)中很難包括對Redis和隊(duì)列的操作。
問題二、向外系統(tǒng)發(fā)送數(shù)據(jù)的過程,可快可慢,在最快的場景中,消息發(fā)送出去,對方立即有相應(yīng)的反饋回來,但本地?cái)?shù)據(jù),可能還沒有保存到數(shù)據(jù)庫中,此時(shí),無法將該數(shù)據(jù)跟數(shù)據(jù)庫中聯(lián)系起來,結(jié)果將會出現(xiàn)數(shù)據(jù)錯(cuò)誤。
一個(gè)解決方案就是,將數(shù)據(jù)庫操作集中到一起放在事務(wù)中處理,將其對應(yīng)的額外操作,放到事務(wù)外面,統(tǒng)一執(zhí)行。
這樣的解決方案,可以保證事務(wù)的完整性,當(dāng)數(shù)據(jù)庫操作失敗的時(shí)候,數(shù)據(jù)庫事務(wù)回滾,其余操作也可以終止。另外也不會發(fā)生消息接收系統(tǒng)反饋結(jié)果太快而導(dǎo)致的數(shù)據(jù)錯(cuò)誤的情況。
但這不是完美的方案。
我們在執(zhí)行業(yè)務(wù)的時(shí)候,“保存并緩存訂單”和“保存并發(fā)送消息”,都是成對的操作,如果將他們割裂,業(yè)務(wù)和代碼將會變得不直觀。
是否可以有個(gè)更好的解決方案呢?
這個(gè)解決方案,我們稱之為延遲執(zhí)行模式。

我們在處理業(yè)務(wù)邏輯的時(shí)候,在事務(wù)中我們正常處理數(shù)據(jù)庫操作,與此同時(shí),在相應(yīng)操作同時(shí)將對應(yīng)的需要延遲執(zhí)行的邏輯定義到一個(gè)延遲執(zhí)行的類中。這個(gè)類我們稱之為DelayedExecutor。并將這個(gè)延遲執(zhí)行對象放到一個(gè)鏈表中,鏈表將在整個(gè)業(yè)務(wù)邏輯的上下游傳遞,在事務(wù)操作結(jié)束后,通過遍歷鏈表來執(zhí)行那些需要延遲執(zhí)行的方法。
該模式的核心在于以下幾個(gè)類和接口
DelayablelService??帶有延遲任務(wù)的業(yè)務(wù)邏輯
public interface DelayablelService <T>?這是一個(gè)接口?
其核心方法是?void doBusiness(T param);??
處理業(yè)務(wù)邏輯,并在處理業(yè)務(wù)邏輯時(shí),將需要延遲執(zhí)行的邏輯定義好
我們所有要執(zhí)行的代碼就是從這里開始
param?是業(yè)務(wù)數(shù)據(jù)參數(shù)? ?
DelayedExecutor?需要被延遲執(zhí)行的邏輯接口
public interface DelayedExecutor
這是一個(gè)接口?其中定義了void execute();方法
該類在業(yè)務(wù)邏輯中,通過匿名內(nèi)部類的方式實(shí)現(xiàn)。將業(yè)務(wù)方法中的數(shù)據(jù)傳入該方法中。
DelayedExecutorHandler?延遲執(zhí)行內(nèi)容管理
public class DelayedExecutorHandler?
一個(gè)管理類,管理DelayedExecutor?
類中有一個(gè)內(nèi)部list?private List<DelayedExecutor> executors;
通過 public void add(DelayedExecutor executor)方法?
在DelayablelService的doBusiness?執(zhí)行以后,
調(diào)用public void handle()方法執(zhí)行延遲執(zhí)行的邏輯。
DelayedCallHandler?執(zhí)行業(yè)務(wù)并調(diào)用被延遲的方法
public class DelayedCallHandler<T>?這是一個(gè)類
public void handle(DelayablelService?businessService, T param)?
通過這個(gè)方法調(diào)用?DelayablelService中的?doBusiness方法,
在?doBusiness執(zhí)行完以后,通過DelayedExecutorHandler?獲取到?延遲執(zhí)行的對象列表遍歷并執(zhí)行其邏輯