2015-06-24 58 views
0

我正在開發基於移動的購物應用。該應用的功能是,用戶將資金存入他的賬戶並在以後支付。 競爭條件是我試圖避免的問題之一。這樣用戶帳戶餘額不會被錯誤計算。交易中避免競爭狀況

我使用的是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是防止競爭狀況發生的保障措施。

回答

0

is_active標誌沒有必要。您需要確保在執行檢查之前鎖定用戶的餘額。

start transaction 
if user has enough balance (lock the rows using a select query with FOR UPDATE) 
    insert into order with user_id, order_id, is_active=1 
    update user balance = balance - item_price where balance >= item_price 
    commit 
else 
    rollback 
    show some error or something 

這可保證在事務處於活動狀態時不會由另一個線程更改用戶餘額。它還保證if user has enough balance將僅針對此時沒有活動的用戶進行評估。

+0

我已經更新了我的問題,以包含另一個將使'is_active'標誌爲必要的情況。請給出意見。謝謝。 –

+0

如果可能有半付款訂單,您可以根據需要用內部賬戶付款,然後通過外部系統進行額外付款。防止用戶同時處理多個訂單隻會部分解決問題,因爲系統的其他部分(可能在將來)可以修改其帳戶餘額。在這個過程中你需要鎖定的東西是餘額而不是訂單。 – Vatev