鎖
業務場景
針對一個賠付工單(由底下小二發起),當金額數量大於一定值以後,針對這筆工單就會有層層審批(風控),先YY一個審批流「TL審批」—>「主管審批」—>「財務審批」.這裡就會存在3種許可權「一審許可權」「二審許可權」「終審許可權」,當這筆工單被小二提交以後就會給小二對應的TL建立一個審批任務,在主管的介面就可以看到相應的審批任務,主管可以點選通過或者拒絕
實現
1.查詢任務,判斷當前角色是否有許可權操作該筆任務,任務沒有完結等一系列校驗
2.驅動狀態機更新工單狀態
3.完結任務
異常場景
場景一
- 操作:主管瘋狂點選通過按鈕3次(前提是按鈕點選一次不會灰顯,就算灰顯也可以通過模擬請求來實現)
- 異常情況:三個點選執行緒都執行完1,然後執行緒1驅動狀態機(通過 + 當前狀態:待TL審批)得到的結果是待主管審批,緊接著執行緒2驅動狀態機(通過 + 當前狀態:待主管審批)得到的結果是待財務審批,然後執行緒3再執行驅動狀態機(通過 + 當前狀態:待財務審批)得到的結果是出賬成功(不考慮多次完結任務會出現異常)
- 異常分析:在該場景中,只要角色擁有「一審許可權」就可以通過漏洞直接把該訂單稽核出賬
-
解決方案:
- 細化狀態機中的每個稽核操作
1.查詢任務,查詢該筆任務對應當前操作型別(TL審批OR主管審批OR財務審批)
---這裡不僅僅是「通過」操作,判斷當前角色是否有對應操作許可權
2.根據當前操作型別+當前狀態驅動狀態機
3.完結任務
- 在查詢任務之前加一個全域性鎖,針對這筆工單進行全域性鎖定(更加優雅)
- 細化狀態機中的每個稽核操作
場景二
- 操作:一個角色同時擁有一審許可權和二審許可權,當他開啟一個工單要進行一審,但是其它主管已經執行了一審的動作,並且更新了一些資訊.因為該角色頁面沒有重新整理獲取不到更新的資訊,然後點選了通過按鈕
- 異常情況:點選通過按鈕就相當於進行了二審,會造成該角色獲取不到最新資訊而產生誤判
-
解決方案:在場景一增加一個全域性鎖的前提下,可以給頁面傳遞一個工單
modifyTime
,在全域性鎖裡面判斷modifyTime
是否一致,如果不一致說明該筆工單已經被更新了,可以給使用者相應的提醒
其它
- 在業務中整個狀態機的流轉都是確定的,所以為了保證狀態流轉正確,所以在更新資料庫狀態的時候,需要帶上關於狀態的樂觀鎖
UPDATE XXX SET status = XXX WHERE id = XXX AND from_status = XXX
- 如果使用的是全域性鎖,那麼每個操作工單的地方都需要加上相應的全域性鎖