У меня возникла проблема, когда я считаю, что процесс повторной индексации цены продукта вызывает исключение тупиковой ситуации в процессе оформления заказа.
Я поймал это исключение в процессе оформления заказа:
Исключение преобразования заказа: 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 () должен произойти после того места, где возникает этот тупик, а не до (согласно ответу Ивана ниже). Тем не менее, транзакция по-прежнему блокируется тупиком (хотя и без ошибочного списания средств с кредитной карты).
Вызов этой функции
$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 Альфа. Все еще ищу обходной путь, пока эта версия не выходит из альфы