2014-01-13 36 views
4

問題的高層次摘要:發出訂單時鎖定庫存表的問題導致由於超時導致訂單失敗。在Magento庫存數量更新過程中使用「FOR UPDATE」

在結帳過程跟蹤,我看到正在執行以下查詢:(意見由我添加)

-- 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才能更新庫存?
  • 爲什麼Magento需要鎖定cataloginventory_stock_item如果cataloginventory_stock_itemUPDATE是原子?
+0

我正面臨同樣的問題。你有沒有發現這種情況下的一些原因? –

回答

3

1)是的,您關於FOR UPDATE的假設是正確的,在cataloginventory_stock_item和catalog_product_entity中選擇的行將被鎖定以供讀取和寫入。也就是說,這些行的其他查詢將被阻止。

2)我不知道,實際上它似乎沒有。也許這是爲了防止競爭條件,當用戶手動更新股票狀態或類似,但我仍然不明白爲什麼它couldn不會被刪除。另一種可能性是原始作者打算支持每個產品的多個庫存項目,並認爲應該鎖定「父」。

3)因爲PHP代碼在發佈更新之前使用加載的值檢查項目是否「可銷售」。如果沒有鎖定,兩個進程可以加載相同的值,然後比賽來更新值。因此,即使它是原子性的,如果在加載數據時出現競態條件,查詢也不會失敗。