僞代碼
場景
用購買某種商品1件(原庫存1000),增加20積分,扣除100元餘額
設計說明
通過日誌表來完成TCC。修改庫存,餘額表要先添加一條記錄到他們的日誌表裏,表要記錄TCC狀態。
通過唯一業務Code去重,保證冪等。
沒有抽象一個活動管理器來管理TCC。
服務
- 本地創建訂單服務createOrder
- 本地插入訂單Mapper層 insertOrder(orderCode)
- 本地其他服務
- 遠程服務是否可以扣除庫存ifReduceStock(orderCode,reduceNumber)
- 遠程服務是否可以扣除餘額ifReduceBalance(orderCode,sum)
- 遠程服務Try扣除庫存,鎖住扣除庫存tryReduceStock(orderCode,reduceNumber)
- 遠程服務Try扣除餘額,鎖住扣除餘額tryReduceBalance(orderCode,sum)
- 遠程服務增加積分
- 遠程服務Confirm扣除庫存confirmReduceStock(orderCode,ReduceNumber)
- 遠程服務Confirm扣除餘額ConfirmReduceBalance(orderCode,sum)
- 遠程服務Cancel扣除庫存,取消佔有資源cancelReduceStock(orderCode,ReduceNumber)
- 遠程服務Cancel扣除餘額,取消佔有資源cancelReduceBalance(orderCode,sum)
- 遠程服務增加積分
- 遠程其他服務
補充服務:扣除日誌超過timeOut時間的記錄狀態設置爲失效Cancel(在是否扣除ifReduce,Confirm操作中調用補充服務)
創建訂單服務createOrder描述
圖1:創建訂單-活動圖
觸發:用戶點擊下單
本地,檢查
- 本地業務服務事務開始
- 本地業務服務同步檢查(調用遠程服務是否可以扣除庫存ifReduceStock(orderCode,reduceNumber), 遠程服務是否可以扣除餘額ifReduceBalance(orderCode,sum),其他)
調用遠程服務是否可以扣除庫存ifReduceStock(orderCode,reduceNumber)說明:
首先,要調用補充服務把日誌中超過timeOut時間的記錄狀態設置爲失效Cancel。
其次,要把日誌狀態爲鎖住Try庫存從剩餘庫存剪掉
餘額同上 - 生成訂單Code(orderCode全世界唯一)
- 同步本地業務插入訂單Mapper層 insertOrder(orderCode),得到訂單
- 其他本地業務
Try
同步調用遠程服務Try扣除庫存tryReduceStock(orderCode,reduceNumber),鎖住扣除庫存1
具體:
遠程添加此次扣除日誌(三種方式:數據庫,Redis,MongoDB),其他判斷是否可以扣除庫存務必減去這個庫存1(從扣除日誌找orderCode相同,狀態爲鎖住Try的操作庫存數)
數據記錄主要字段,值:
orderCode(用於去重)
原庫存,值1000
此次操作庫存,值1
操作時間(一個用途,用於計算超過某個值timeOut後,把此條記錄狀態設置爲失效Cancel)
狀態(鎖住Try,確認Confirm,失效Cancel),值鎖住Try同步調用遠程服務Try扣餘額tryReduceBalance(orderCode,sum),鎖住扣除餘額100
具體同庫存- 同步調用遠程服務Try增加積分
具體同庫存(比庫存簡單一些) - 有任何錯誤或者異常回滾本地事務。結束。
Confirm,Cancel
- 同步調用遠程服務Confirm真正扣除庫存confirmReduceStock(orderCode,ReduceNumber)
具體:
首先,要調用補充服務把日誌中超過timeOut時間的記錄狀態設置爲失效Cancel
其次,扣除日誌裏找到orderCode,此次操作庫存爲ReduceNumber1,狀態爲鎖住Try記錄,根據此條記錄扣減庫存。 - 失敗了。1)Cancel扣除庫存,取消佔有資源2)回滾本地事務。結束。
- 同步調用遠程服務Confirm扣除餘額ConfirmReduceBalance(orderCode,sum)
- 失敗了。
1)Cancel扣除餘額,取消佔有資源
2)遠程調用服務Cancel扣除庫存cancelReduceStock(orderCode,ReduceNumber)還原庫存
具體還原庫存:
除日誌裏找到orderCode,此次操作庫存爲ReduceNumber1,狀態爲確認Confirm記錄,根據此條記錄還原庫存。
3)回滾本地事務。結束。 - 同步遠程調用增加積分如果失敗同樣要還原庫存和餘額
- 本地業務服務事務結束,提交。
問題
1.爲什麼有些地方可以不進行Cancel操作?因爲超過TimeOut會Cancel。
2.秒殺活動等高併發怎麼辦?秒殺情況下,應在下單前的購買和加入購物車操作做限制。添加一個隊列,隊列中請求已把庫存買光,就不允許進入隊列走下單。只有進入隊列的纔可以下單。使用Redis實現。