Java生鮮電商平台-電商虛擬幣的充值與消費思考


Java生鮮電商平台-電商虛擬幣的充值與消費思考

 

項目背景

最近由於項目業務原因,需要為系統設計虛擬幣的充值及消費功能。公司內已經有成熟的支付網關服務,所以重點變成了如何設計項目內虛擬幣的充值流程,讓整個充值流程都實現冪等,確保用戶的虛擬幣余額不會重復增加或扣減。

商品購買及支付流程

 

 
微信支付時序圖

(1)用戶購買商品,商戶后台請求生成支付訂單並返回相關信息到客戶端。
(2)客戶端根據返回的信息喚起支付SDK,用戶確認支付。
(3)用戶完成支付后,支付系統會異步通知商戶后台支付結果。
(4)商戶后台接收支付回調,在回調接口內完成自己的業務邏輯。
(5)客戶端在支付完成后延時一定時間從商戶后台查詢支付結果,此時若尚未接收到支付回調,可主動同步支付結果( 保底策略)。

支付寶支付流程和微信支付類似,此處省略。正常情況下支付回調都會在毫秒級別進行通知回調。

虛擬幣充值流程

虛擬幣充值流程會嵌套支付回調流程中。若虛擬幣沒有完成完整的業務流程,支付系統會進行重試。因此業務流程需要支持冪等。


 
虛擬幣充值流程

在實踐過程遇到以下問題並最終得到解決:
(1)如何支持訂單按用戶維度分表?
支付回調信息只包括訂單ID信息,在這種情況下一般只能根據訂單ID進行分表。考慮到訂單會越來越多,我們一開始就把訂單按用戶維度進行分表。一般情況下按用戶維度的查詢是很多的,而單純按訂單維度的查詢會比較少。所以在預下單的時候把用戶ID信息寫入attach附加信息,支付回調時會攜帶上原先的附加信息,這樣就可以知道用戶及訂單ID信息,完成后續操作。

在后來的優化中,訂單ID生成時預留低位段存儲用戶訂單表ID信息,這樣完全不依賴附加信息進行傳遞,在用戶進行自動扣費授權時的回調通知也可以適用。

(2)虛擬幣如何做事務操作?
若只有用戶虛擬幣的數量信息,很容易會出現錯誤的重復操作。因此需要流水表配合進行事務操作,當流水表已經有相同的記錄時說明當前操作是重復的,需要回滾虛擬幣數值。通過數據庫的單機事務即可實現虛擬幣的正確變更,支持重入。
(3)如何做虛擬幣的版本控制?
我們虛擬幣每次變更都會對應一個版本號,在對虛擬幣的並發操作時一般都是通過判斷version是否符合預期時才進行數據變更。這個和樂觀鎖的控制類似,可是在這種情況下容易出現死鎖,尤其是數據庫性能差更容易觸發。因此不再嚴格判斷version版本號,只需要變更后的虛擬幣數量不小於0即可,所有符合這個條件的變更都視為有效變更。這個情景適合不用版本號,只更新是做數據安全校驗,適合庫存模型,性能更高。

update table_xxx set avai_amount=avai_amount+:deltaAmount where user_id=:userId and avai_amount+:deltaAmount >= 0

有虛擬幣消費才會出現並發修改,因此我們只需要嚴格控制虛擬幣不出現余額不足以扣除的情況。

蘋果內購虛擬幣充值流程

用戶在應用內購買商品時,客戶端可以獲取到用戶ID、交易憑證receipt和交易ID等信息。整體購買流程和Android端差異比較大,因為對receipt驗證流程參考Android下單流程做了拆解,更容易做到重入。
(1)客戶端獲取到充值列表;
(2)客戶端支付成功后提交交易憑證receipt給服務端驗證,服務端創建對應的憑證和訂單記錄,更新狀態,完成充值;


 
蘋果內購充值流程

蘋果內購有以下事項需要注意:
(1)如何避免receipt被重復使用?
iOS客戶端支付成功后能獲取到transactionId和receipt信息,兩者唯一對應。因此服務端在驗證receipt有效后,可創建對應的transaction記錄,根據transactionId進行分表,transactionId作為唯一鍵。這樣可避免receipt被重復使用。
(2)transaction和訂單記錄的映射關系
訂單記錄包含渠道transactionId信息,這樣在創建transaction記錄后也可以唯一綁定到訂單信息,避免重復創建訂單。

設計總結

在設計訂單系統時冪等性是首要考慮的問題,需要嚴格保證金額的准確性,不能給用戶多扣款或多打款。一般情況下我們通過數據庫單機事務和冪等重試等方式提高訂單系統的健壯性。根據需要也可以選用消息隊列等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM