2016-02-03 9 views
4

У меня есть 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

ответ

1

Есть несколько вещи, которые вы здесь делаете неправильно. Во-первых, нет причин для того, чтобы вы запирали таблицы таблицами. Одна из целей дизайна InnoDB заключается в том, что она имеет блокировку на уровне строк.

Во-вторых, вы должны использовать инструкцию SELECT FOR UPDATE для блокировки строк, с которыми работаете, затем выполните ваши UPDATE и COMMIT.

Я также не понимаю, почему вы присоединяетесь к продуктам в категориях и меню, когда эти таблицы просто информативны относительно этого обновления. Это похоже на функцию обработки данных.

+0

спасибо за ответ, на самом деле я использовал select для обновления, однако я столкнулся с этим тупиком http://stackoverflow.com/questions/5432370/mysql-innodb-dead-lock-on-select-with-exclusive- lock-for-update/5432714 # 5432714 и потому, что я не мог удалить первичный ключ (как описано в этом ответе), я решил сделать блокировку на уровне таблицы. Что касается категорий и manus, я просто хотел описать, как он работает, чтобы ничего не пропустить, информация этой таблицы необходима, я не получаю их просто без причины, но это была ненужная информация - как мне нужна эта информация, поэтому Я не включил в вопрос – dav

 Смежные вопросы

  • Нет связанных вопросов^_^