У меня есть menus
, categories
и products
столов. Я использую mysql 5.5, все таблицы являются innoDB, и во всех случаях id является первичным ключом (int) с автоинкрементами.Mysql - Неисправность сериализации: 1213 Тупик обнаружен при попытке получить блокировку; попробуйте перезапустить транзакцию
menus table
id, name, status
categories table
id, menu_id, name
products table
id, menu_id, category_id, status, name, url, content
Несколько сценариев могут выполняться параллельно, выполняя тот же файл php, который содержит следующую логику.
START TRANSACTION;
SET autocommit = 0;
LOCK TABLES products WRITE, categories WRITE, menus WRITE;
SELECT
p.`id`,
p.`name`,
p.`url`,
p.`status`,
c.`id` cat_id,
c.`name` cat_name,
m.`id` `menu_id`,
m.`name` menu_name
FROM
products p
LEFT JOIN categories c
ON p.`subcategory_id` = c.`id`
LEFT JOIN menus m
ON p.`menu_id` = m.`id`
WHERE p.`status` = 0 LIMIT 1
если после выбора результата можно найти, это статус обновляется до 1 (в противном случае я откатить и освободить замки)
UPDATE products SET status = 1 WHERE id = [product_id];
если последний запрос успешен я бегу
COMMIT();
UNLOCK TABLES;
В противном случае
ROLLBACK();
UNLOCK TABLES;
После этого скрипт делает завиток запрос к URL, что продукты, чтобы получить содержание от него и обновить строку продукта соответственно
// making curl request (might take a few dozen seconds, because proxy is being used and sometimes because of proxy failure the request is attempted again)
trying to update the products table
UPDATE products SET content = [received content], status = 2 WHERE id = [product_id]
Итак, сценарий приобретает X блокировку указанных таблиц, выборка один строка из таблицы продуктов, которая имеет статус 0 (средство - TODO), пытаясь установить свой статус на 1 (означает «ОЖИДАНИЕ») и разблокирует таблицы. После этого пытается выполнить некоторую логику в php и, наконец, пытается обновить таблицу продуктов - обновить столбец контента, а также статус до 2 (означает DONE).
Если я бегу, как 5 сценариев параллельно, через несколько минут бега на последней стадии (обновление продукта до DONE) Я получаю эту ошибку
Error: SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when try to get lock; try restarting transaction
Я понимаю общую идею тупиков, когда 2 транзакции ждут друг друга, чтобы обновить одни и те же строки в обратном порядке, однако я не могу выяснить причину взаимоблокировки в этом случае. Я имею в виду, что скрипты работают и блокируют таблицы в том же порядке, поэтому, если один скрипт заблокировал таблицы products
(и другие), получив эксклюзивную блокировку, другие скрипты должны ждать в очереди, чтобы эти блокировки были выпущены, поэтому он не должен вызывать тупиковый.
С другой стороны, каждый скрипт выбирает продукты со статусом -> 0 и пытается обновить до 1 и в течение того же «сеанса» от 1 до 2, поэтому я не вижу, как это может быть причиной тупика. Что мне здесь не хватает?
редактировать:
Хотя я не упомянул, как я использую категории и информации меню Tables', но мне нужно получить их, а также, их использование не важно, так как я не делаю какой-либо db с ними.
Я использовал для использования на уровне строк блокировки SELECT FOR UPDATE
, однако я получаю тупики, как в этом вопросе MySQL InnoDB dead lock on SELECT with exclusive lock (FOR UPDATE), поэтому, я должен был изменить код таблицы уровня блокировки
Thanks
спасибо за ответ, на самом деле я использовал select для обновления, однако я столкнулся с этим тупиком http://stackoverflow.com/questions/5432370/mysql-innodb-dead-lock-on-select-with-exclusive- lock-for-update/5432714 # 5432714 и потому, что я не мог удалить первичный ключ (как описано в этом ответе), я решил сделать блокировку на уровне таблицы. Что касается категорий и manus, я просто хотел описать, как он работает, чтобы ничего не пропустить, информация этой таблицы необходима, я не получаю их просто без причины, но это была ненужная информация - как мне нужна эта информация, поэтому Я не включил в вопрос – dav