我遇到了一个问题,我认为产品价格重新索引编制过程在结帐过程中导致了死锁异常。
我在结帐过程中捕获了此异常:
订单转换异常:SQLSTATE [40001]:序列化失败:1213尝试获取锁时发现死锁;否则,错误代码为:尝试重新启动事务
不幸的是,由于捕获异常的原因,我没有完整的堆栈跟踪信息,但是通过检查INNODB状态,我能够找到死锁:
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(47447, 56678)) FOR UPDATE
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 329624 n bits 352 index
`PRIMARY` of table `xxxx`.`catalog_product_entity`
SQL请求表锁最终是从 Mage_CatalogInventory_Model_Stock::registerProductsSale()
尝试获取当前清单计数以使其递减时生成的。
发生死锁时,“产品价格重新索引”过程正在运行,我假设它对catalog_product_entity table
导致死锁的读取锁定。如果我正确地理解了死锁,那么任何读取锁都会导致死锁,但是产品价格重新索引会在相当长的时间内保持该锁,因为该站点有约50,000个产品。
不幸的是,此时,在结帐代码流中,已通过自定义付款模块向客户的信用卡收费,并且创建相应的订单对象失败。
我的问题是:
- 定制支付模块逻辑是否有问题?也就是说,是否存在确保Magento在将付款委托给付款方式(信用卡)之前可以将报价免费转换为订单例外的流程?
编辑: 似乎支付模块逻辑确实有问题,因为对$ paymentmethod-> authorize()的调用应在发生此死锁的位置之后而不是之前发生(按照下面的Ivan的回答)。但是,交易仍将被僵局阻止(尽管不会向信用卡收取错误费用)。
此函数调用
$stockInfo = $this->_getResource()->getProductsStock($this, array_keys($qtys), true);
中Mage_CatalogInventory_Model_Stock::registerProductsSale()
使其锁定读,这是多么危险将是使之成为非锁定读?在网络上搜索答案时,有两个地方建议在网站很热时不运行完全重新索引;似乎不是一个好的解决方案;导致表死锁和锁争用的索引问题是Magento中的一个已知问题,是否有解决方法?
编辑: 似乎这里剩下的问题是第三个问题中的一个;重新索引会导致表死锁。寻找解决方法。
编辑:死锁不是问题本身,而是问题的解决本身应该成为焦点,这一概念很有意义。进一步调查以找到代码中的点以捕获死锁异常并重新发出请求。在Zend Framework DB适配器级别执行此操作是一种方法,但我也在寻找一种方法来在Magento代码中执行此操作以简化可维护性。
此线程中有一个有趣的补丁:http : //www.magentocommerce.com/boards/viewthread/31666/P0/似乎可以解决相关的死锁条件(但不是专门解决此问题)。
编辑:显然,死锁已在CE 1.8 Alpha中得到了解决。仍在寻找解决方法,直到此版本退出Alpha