1. 程式人生 > >一種登記賬後余額的處理方法

一種登記賬後余額的處理方法

uuid 字段 優化 鎖定 sel chan 代碼 count acc

支付系統的記賬業務,需要登記每筆記賬流水的賬後余額。
在大規模並發條件下,簡單使用樂觀鎖或者悲觀鎖都回嚴重的鎖定數據庫,導致性能變慢,下面介紹優化前和優化後的兩種處理思路。

第一種方案,使用樂觀鎖
實現過程:
Step1:從賬戶中獲取最近余額以及賬戶當前版本號,代碼如下:
Select version, balance from account where customer_no=?
Step2:創建賬戶流水
Insert into account_flow(version, amount, balance, customer_no) values(:version+1, amount, balance+amount, customer_no)
Step3:更新賬戶余額
Update account set version=version+1, balance = balance + amount where customer_no=:customer_no and version=:version


在並發量小的時候,這樣寫基本沒有問題,可以保證每筆交易的記賬流水都是OK,然而,並發大的時候,會發現Step3中的紅色部分的條件,完全Hold不住了,還沒等待一筆交易完成,可能version已經變化了不止一次

第二種方案,使用觸發器
實現過程:
Step1:創建過程表
Create table account_his(account_id, version, pre_version, balance, pre_balance, uid)
字段分別是:賬戶ID、當前版本號、前一版本號、當前余額、前一版本余額、唯一ID(後面解釋)
Step2:創建針對account的觸發器
Create or replace trigger account_change_trigger before update on account for each row
Begin
insert into account_his values (:old.account_id,:new.version,:old.version,:new.balance, :old.balance,:new.uid)
End
Step3:修改記賬過程
1、生成uid=uuid
2、更新賬戶余額:update account set uid=:uid,balance=balance+amount where account_id=xx
3、登記記賬流水:insert into account_flow values(account_id, amount, uid),註,此處暫時不登記余額
4、使用定時器,從account_his中更新account_flow的余額:update account_flow set balance=account_his.balance where account_his.uid=account_flow.uid

雖然觸發器對數據庫性能存在一定的損失,但這個好處還是明顯的。

一種登記賬後余額的處理方法