问题的高级别摘要:在下订单时导致库存表锁定问题导致订单因超时而失败。
通过结帐流程,我看到正在执行以下查询:(我添加的评论)
-- 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)
我对FOR UPDATE
语句的SELECT
修饰符的理解是,SELECT
中返回的表中的所有行都将被锁定(读取和写入?),直到事务处理为止提交。
根据我对MySQL的理解,cataloginventory_stock_item
查询具有qty
列的计算值(即该值未在PHP中计算并传递到查询中,新列)值基于执行查询时的现有列值表示它不会受到竞争条件的影响。
我的问题是:
catalog_product_entity
以更新股票?cataloginventory_stock_item
cataloginventory_stock_item
是原子的话,为什么Magento需要锁定UPDATE
?答案 0 :(得分:4)
1)是的,您对FOR UPDATE的假设是正确的,在cataloginventory_stock_item和catalog_product_entity中选择的行将被锁定以进行读写。也就是说,这些行的其他查询将被阻止。
2)我不知道,事实上它似乎没有..也许这可以防止用户手动更新库存状态或类似情况时的竞争条件,但我仍然不明白为什么它不能'被删除。另一种可能性是原作者打算支持每个产品的多个库存商品,并认为应该锁定“父母”。
3)因为PHP代码在发布更新之前使用加载的值检查项是否是“可销售的”。如果没有锁定,两个进程可以加载相同的值,然后竞争更新值。因此,即使它是原子的,如果在加载数据时存在竞争条件,查询也不会正常失败。