问题的高级摘要:在下订单时获取有关锁定库存表的问题,导致订单因超时而失败。
通过结帐流程,我看到正在执行以下查询:(我添加的评论)
-- Lock stock and product tables
SELECT `si`.*, `p`.`type_id` FROM `cataloginventory_stock_item` AS `si`
INNER JOIN `catalog_product_entity` AS `p` ON p.entity_id=si.product_id
WHERE (stock_id=1) AND (product_id IN(28775, 28777)) FOR UPDATE
-- Perform the actual stock update
UPDATE `cataloginventory_stock_item`
SET `qty` =
CASE product_id
WHEN 28775 THEN qty-2
WHEN 28777 THEN qty-1
ELSE
qty
END
WHERE (product_id IN (28775, 28777)) AND (stock_id = 1)
我对 SELECT
语句的 FOR UPDATE
修饰符的理解是,SELECT
中返回的表中的所有行都将被锁定(读和写?)直到事务被提交。
根据我对 MySQL 的理解,cataloginventory_stock_item
查询具有 qty
列的计算值(即该值未在 PHP 中计算并传递到查询时,新的列值基于执行查询时的现有列值)意味着它不会受到竞争条件的影响。
我的问题是:
- 我的假设是否正确?
- 为什么 Magento 需要锁定
catalog_product_entity
才能更新库存? - 如果
cataloginventory_stock_item
UPDATE
是原子的,为什么 Magento 需要锁定cataloginventory_stock_item
?
最佳答案
1) 是的,您关于 FOR UPDATE 的假设是正确的,在 cataloginventory_stock_item 和 catalog_product_entity 中选择的行将被锁定以进行读写。也就是说,对这些行的其他查询将被阻止。
2) 我不知道,事实上它似乎没有..也许这是为了防止用户手动更新库存状态或类似情况时出现竞争条件,但我仍然不明白为什么它不能'不会被删除。另一种可能是原作者打算支持每个产品的多个库存项目,并认为“父级”应该被锁定。
3) 因为 PHP 代码在发布更新之前使用加载的值检查项目是否“可销售”。如果没有锁定,两个进程可能会加载相同的值,然后争先恐后地更新该值。因此,即使它是原子的,如果在加载数据时存在竞争条件,查询也不会正常失败。
关于mysql - 在 Magento 库存数量更新期间使用 "FOR UPDATE",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21092325/