在Magento库存数量更新期间使用“FOR UPDATE”

时间:2014-01-13 13:18:42

标签: mysql magento locking

问题的高级别摘要:在下订单时导致库存表锁定问题导致订单因超时而失败。

通过结帐流程,我看到正在执行以下查询:(我添加的评论)

-- 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中计算并传递到查询中,新列)值基于执行查询时的现有列值表示它不会受到竞争条件的影响。

我的问题是:

  • 我的假设是否正确?
  • 为什么Magento需要锁定catalog_product_entity以更新股票?
  • 如果cataloginventory_stock_item cataloginventory_stock_item是原子的话,为什么Magento需要锁定UPDATE

1 个答案:

答案 0 :(得分:4)

1)是的,您对FOR UPDATE的假设是正确的,在cataloginventory_stock_item和catalog_product_entity中选择的行将被锁定以进行读写。也就是说,这些行的其他查询将被阻止。

2)我不知道,事实上它似乎没有..也许这可以防止用户手动更新库存状态或类似情况时的竞争条件,但我仍然不明白为什么它不能'被删除。另一种可能性是原作者打算支持每个产品的多个库存商品,并认为应该锁定“父母”。

3)因为PHP代码在发布更新之前使用加载的值检查项是否是“可销售的”。如果没有锁定,两个进程可以加载相同的值,然后竞争更新值。因此,即使它是原子的,如果在加载数据时存在竞争条件,查询也不会正常失败。