避免交易中的竞争条件

时间:2015-06-24 09:45:54

标签: mysql race-condition

我正在开发基于移动的购物应用。该应用程序的作用是,用户将钱存入他的帐户并稍后使用。 竞争条件是我试图避免的问题之一。这样用户帐户余额不会被误算。

我正在使用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是防止发生种族情况的保障措施。

1 个答案:

答案 0 :(得分: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仅针对目前没有活动交易的用户进行评估。