php - 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”,这将在行上设置一个排他锁,但这也阻止了一个普通用户正在检查可用性(在产品页面上)以防止瞬时加载,而我而不是让他们快速加载页面而不是第二个准确的库存。所以基本上我希望读锁只适用于将在同一事务中更新值的客户端。
我想要的是可能的,还是我需要用我得到的东西工作?提前致谢!
解决方案
有两种方法可以解决问题:
- 您可以在 MySQL 中使用一个函数,该函数将更新库存并给出错误“对不起,您的产品刚刚缺货!”,当扣除后的余额低于 0 时。
或(首选方式)
- 您可以在 MySQL中使用锁定。在这种情况下,它应该是一个写锁。写锁将禁用其他读取请求(由第二人),直到锁被释放(由第一人)。
希望对你有帮助!
推荐阅读
- passport.js - hasura auth hook 不转发客户端 cookie
- sql - 如何将逗号分隔的数据从一列拆分为多行
- c# - 将数据插入嵌套列表 C#
- mongoose - 如何使用 jest 检查调用次数的猫鼬模拟函数?
- python - Python 在不停止执行代码的情况下捕获自定义警告类
- javascript - 如何使用 Javascript 将特定文件附加到 FormData?
- algorithm - 随机选择顶点作为信标
- stripe-payments - Stripe:如何在一系列价格中保留付款
- discord - 在 v13 API 中使用 .createInvite 方法时出现空错误
- discord.js - 绕过发送提醒的机器人的方法