我正在開發基於移動的購物應用。該應用的功能是,用戶將資金存入他的賬戶並在以後支付。 競爭條件是我試圖避免的問題之一。這樣用戶帳戶餘額不會被錯誤計算。交易中避免競爭狀況
我使用的是mysql 5.5,php。
這就是我所提出的。
create table orders ( order_id int, user_id int, title varchar, item_price decimal, is_active int default null, constraint primary key (order_id), constraint unq unique (user_id, is_active) )
的想法是設置USER_ID唯一約束和IS_ACTIVE使得只有一個活動的順序(存錢或使用平衡)可以被處理。活動訂單將is_active
設置爲1. is_active
已更新爲時間戳記,因此一旦完成訂單就會滿足唯一約束條件。存款是類似的邏輯。
這裏是要購買的項目與賬戶餘額的僞代碼:
if user has enough balance,
start transaction
insert into order with user_id, order_id, is_active=1
update user balance = balance - item_price where balance >= item_price
commit
if transaction success,
update order set is_active= current_timestamp where user_id=, order_id=
有沒有這種邏輯的任何問題?
,或者可以不與該行的唯一約束來避免競爭條件: update user balance = balance - item_price where balance >= item_price
更新1
我已經錯過了,這將使事情變得更加複雜的情況下。詳細信息如下:
當物品價格高於其賬戶餘額時,用戶可以選擇通過外部支付服務付款。
// first http request
try to cancel any previous active external payment by the same user
if user has enough balance,
get a secure token from external payment service
insert into order with user_id, order_id, is_active=1
// second http request
user paid and external payment service notifies my backend about the success payment. Then
start transaction
update user balance = balance - balance_pay_amount where balance >= balance_pay_amount
update order set is_active= current_timestamp where user_id=, order_id=
commit
由於支付和賬戶餘額更新發生在一系列請求中。交易將不會在這裏工作。
因此,在創建另一個活動訂單之前,我選擇取消之前由同一用戶通過外部服務支付的活動訂單。這將會減慢在短時間內無法提交多個訂單的用戶的負面影響。如果任何現有的廢棄活動訂單阻止用戶發出新訂單,這可用作額外的清理。
is_active
是防止競爭狀況發生的保障措施。
我已經更新了我的問題,以包含另一個將使'is_active'標誌爲必要的情況。請給出意見。謝謝。 –
如果可能有半付款訂單,您可以根據需要用內部賬戶付款,然後通過外部系統進行額外付款。防止用戶同時處理多個訂單隻會部分解決問題,因爲系統的其他部分(可能在將來)可以修改其帳戶餘額。在這個過程中你需要鎖定的東西是餘額而不是訂單。 – Vatev