用戶確認支付后,支付系統異步調用交易系統,交易系統更新交易狀態,通知商家發貨。如果交易系統超時未響應支付系統,支付系統會進行重試。有可能這時交易系統已經通知商家發貨,這次的重試會讓商家發貨兩次,這是不可以接受的。
這時,需要引入一個防重操作,例如,每次更新交易狀態,先查詢是否是初始狀態,如果是,就更新為成功,並且通知商家發貨。如果不是初始狀態,就不通知商家發貨。以下是偽代碼演示:
1.select * from order_info where id = "20201020"
2.Java代碼判斷status == '初始' 執行3,否則返回
3.update order_info set status = '成功' where id = '20201020'並且發貨
上面的防重操作並沒有考慮並發的情況,當有兩個請求都執行了1,都拿到初始狀態,他們就都會去通知發貨。
悲觀鎖方案
查詢時加行鎖。
begin transaction
1.select * from order_info where id = "20201020" for update 加record lock
2.Java代碼判斷status == '初始' 執行3,否則返回
3.update order_info set status = '成功' where id = '20201020'並且發貨
commit
樂觀鎖方案
在update時加一個state = '初始'條件,如果state為初始,則影響行數為1,如果state為成功,則影響行數為0。通過最后一個更新操作的影響行數來判斷是否返回。
begin transaction
1.select * from order_info where id = "20201020" for update 加record lock
2.Java代碼判斷status == '初始' 執行3,否則返回
3.update order_info set status = '成功' where id = '20201020' and state = '初始',判斷影響行數,若為1則發貨
commit
OS:我尋思這不是重復發貨嗎。。。