2015-07-21 65 views
2

我写了一个bash脚本,试图发送一些POST请求到我的网站。在网站上我的POST请求处理我有这样一个逻辑:PHP/MySQL竞态条件问题

$std = new \stdClass(); 
$std->ok = false; 
$order = getOrderById(id); // table: orders 
$user_id = user_id; 
if (!empty($order)) { 
    if (!orderIsntPerformedByUser($user_id, $order->id)) { // table: performed_orders 
     updateUserData($user_id, ['user_balance', 'user_balance+1']); // table: users 
     performOrderByUserId($order->id, $user_id); // table: performed_orders 
    } 
} 
echo json_encode((array)$std); 
return; 

bash脚本:

for i in {1..5} 
do 
    curl 'http://example.com/handlePostRequest' --form-data="id=1" & 
done 

它发出的背景5个POST请求和我的网站的响应瞬间。所有请求都在同一时间执行,并且少数请求会从服务器收到“真实”响应。

我认为我需要使用事务机制来避免这种情况?或者如何避免用户请求之间的一些延迟呢?解决它的最好方法是什么?我试图为类似的网站做这个动作,并且在请求之间得到了延迟。

非常感谢你,对我的坏英语感到抱歉。

+0

你受到并发性的打击。您正在检查脚本中的数据有效性 - 这是错误的。数据使用数据库进行验证。你有一大堆误报。这样做的方式是只需插入数据库。 'order_id'作为一个唯一的键,所以如果发生同样的'order_id'插入,你更新记录。 MySQL的语法是'INSERT INTO ... ON DUPLICATE KEY UPDATE'。它解决了你所有的问题。 [这里是链接到MySQL手册](https://dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html)关于我提到的语法。 –

回答

3

我会扩大我的评论。你在服务器上做错了事。您使用PHP来验证订单是否在数据库中,但PHP脚本不是数据权限 - MySQL是。 MySQL的工作就是照顾数据。您的要求是您插入到表格中,并且如果该记录存​​在与order_id - 更新current_balance

这是通过在order_id上放置​​来实现的。然后,您的查询看起来是这样的:这种方法的

INSERT INTO orders (order_id, current_balance) VALUES (1, 13.37) ON DUPLICATE KEY UPDATE current_balance = current_balance + 333.333 

优点:

  • 数据库负责数据(这是它的工作)
  • 并发问题不会发生
  • 数据完整性
  • 您有较少的代码需要照顾
+0

Btw更新用户平衡这种方式是坏架构!这是更好的方法: 'START TRANSACTION; INSERT INTO orders(order_id,current_balance)VALUES(1,13.37)ON DUPLICATE KEY UPDATE current_balance = current_balance + 333.333; INSERT INTO transaction_history ....; COMMIT;' – kirugan

+1

@kirugan它的体系结构不错,所有的InnoDB表都以自动提交模式运行,这意味着它们在自己的事务中。您不必隐式启动一个。因此,添加'START TRANSACTION'是无用的,它们已经在交易。请阅读手册。 –

+0

@ N.B。,对于错误的描述感到抱歉。我有一个表格存储用户执行的命令。我需要检查用户是否已经执行了订单,然后更新他的余额。另外,如果有一定数量的用户执行了订单,那么我需要从订单表中删除此订单。 – Grmice