多並發時支付如何保持賬戶余額的一致性?


轉載:http://costlend.com/2016/03/14/dispatch-pay-balance-keep-consistence/


不管是電商,還是O2O業務都會涉及到支付,而且多速情況下流量比較大,尤其是在做活動的時候。一般支付系統主要有充值,扣費,提現,轉賬等功能,那么在有些業務場景下,尤其是多並發的情況下,我們在做扣費業務操作時該怎樣去保持賬戶余額的一致呢?

Java開發人員可能第一個想法就是在調用扣減的DAO的方法上加上一個synchronized關鍵字,這個解決辦法在單節點應用部署是也許能生效管用,但是在我們實際的應用場景中,一般都是集群,多節點部署的應用,這個時候該如何解決呢?

我們有一張賬戶表tb_account

field type desc
uid bigint 用戶id
balance decimal 余額
update_time datetime 表數據更新時間

扣費之前,我們要先查詢一下賬戶的余額是否足夠抵扣,然后再做真正的減扣。
大致的過程如下:

  1. select balance from tb_account where uid=100;
  2. 程序判斷balance的值是否足夠抵扣。
  3. update tb_account set balance = balance - 28.00, update_time = sysdate() where uid=100;
    通常情況下,這種余額判斷方法在高並發且不加鎖的情況下是非常不可靠的。所以在做扣費操作時要考慮到並發扣費的情況,允許讓其並發扣費,但是不應該允許賬戶余額為負數。轉賬的話也是一樣,相當於先從一個賬戶扣費,再給另一個賬戶充值,都必須要在一個事務內完成。
    可以使用一個存儲過程來把這些步驟統一起來。下面的存儲過程親測可用。
 1 create procedure proc_account_balance_dec ( in_money decimal(8,2), in_uid bigint, OUT status int )  
 2 BEGIN  
 3 
 4 DECLARE from_account_balance decimal(8,2);  
 5 
 6 START TRANSACTION;  
 7 
 8 SELECT balance INTO from_account_balance FROM tb_account  
 9     WHERE uid = in_uid FOR UPDATE;  
10 
11 IF from_account_balance>=in_money THEN   
12     UPDATE tb_account SET balance = balance - in_money , update_time = sysdate()  
13         WHERE uid = in_uid;  
14     COMMIT;  
15 
16     SET status=1;  
17 ELSE   
18     ROLLBACK;  
19     SET status=0;  
20 END IF;  

 

 



免責聲明!

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



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