首页 > 解决方案 > Mysqli/PHP 防止某些脏读

问题描述

目前我遇到了一个问题,我正在努力解决这个问题(尽管我可能想多了)。

目前,我的 SQL DB 中有一个表,其中包含一些产品和库存量。人们可以访问产品页面,或者订购它(如果您是管理员,也可以更新它)。但现在我害怕比赛条件。

订单流程如下:

1)会话开始一个事务。

2)它获取当前可用的单位数量。

3)它检查要订购的数量是否可用,然后减去该数量。

4)它用新的“总金额”值更新产品表。这是非常短的代码(不使用准备好的语句等)。

BEGIN;
SELECT amount FROM products WHERE id=100;
$available=$result->fetch_array(MYSQLI_NUM)[0];
if($order<=$available){
    $available-=$order;
    UDPATE products SET amount=$available WHERE id=100;
}
//error checking and then ROLLBACK or COMMIT

我现在的问题是:我该怎么做才能防止在第 2 步中出现脏读数,以及在第 4 步中写回错误值?

示例:如果 1 人订购了 10 件产品 A,而在第 3 步时,第二个人也订购了 5 件产品 A。所以在第 2 步中它仍然会获得“旧”值并使用它,并且因此在步骤 4 中恢复了错误的数字。

我知道我可以使用“SELECT .... FOR UPDATE”,这将在行上设置一个排他锁,但这也阻止了一个普通用户正在检查可用性(在产品页面上)以防止瞬时加载,而我而不是让他们快速加载页面而不是第二个准确的库存。所以基本上我希望读锁只适用于将在同一事务中更新值的客户端。

我想要的是可能的,还是我需要用我得到的东西工作?提前致谢!

标签: phpmysqli

解决方案


有两种方法可以解决问题:

  1. 您可以在 MySQL 中使用一个函数,该函数将更新库存并给出错误“对不起,您的产品刚刚缺货!”,当扣除后的余额低于 0 时。

或(首选方式)

  1. 您可以在 MySQL中使用锁定。在这种情况下,它应该是一个写锁。写锁将禁用其他读取请求(由第二人),直到锁被释放(由第一人)。

希望对你有帮助!


推荐阅读