LINUX.ORG.RU

MySQL Error #1442

 , , ,


0

1

Есть два триггера, которые не могу заставить работать вместе.

Первый

DELIMITER //
CREATE TRIGGER `change_status_to_failed` AFTER UPDATE ON `tasks_dicts` 
FOR EACH ROW 
BEGIN
   	DECLARE dicts_count INT;

	SELECT COUNT(*) INTO dicts_count FROM (SELECT * FROM tasks_dicts WHERE status NOT IN ('1') AND net_id=NEW.net_id) as alias;
	IF (dicts_count=0) THEN
		UPDATE tasks SET status='3' WHERE id=NEW.net_id;
	END IF;	
END
//
DELIMITER ;

Второй

DELIMITER //
CREATE TRIGGER `delete_success_failed` AFTER UPDATE ON `tasks` 
FOR EACH ROW 
BEGIN
   	DELETE FROM tasks_dicts WHERE net_id IN(SELECT id FROM tasks WHERE status IN('2', '3'));
END
//
DELIMITER ;

При изменении поля в tasks_dicts ловлю ошибку

#1442 - Can't update table 'tasks_dicts' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. 

Гугл говорит, что это происходит от того, что таблица на время выполнения триггера блокируется, но как 1 влияет на 2. Буду рад любым советам.

По-отдельности, первый и второй триггер работают как надо.

З.Ы. Переезжать на другую БД не могу, сроки проекта поджимают.



Последнее исправление: AtomicMan (всего исправлений: 2)

Да, не даёт. Причём во втором триггере можно писать что угодно.

DELETE FROM tasks_dicts WHERE net_id = 9992;
т.е. - любое шевеление таблицы заблокировано, даже если никакого отношения не имеет к условиям шевеления.

Что-то подобное было у меня. Тогда это обходил через механизмы CREATE EVENT. Внутри триггера никак не трогал таблицу, а создавал флаги в промежуточной таблице, которые по EVENT потом уже чистились. Еще и флаг блокировки, помню, ставил чтобы EVENT ждал, если вдруг попадал на работу триггера.

Правда в итоге, людям отдал всю ту беду в PostgreSQL. Там проще оказалось с этими вложенными триггерами. (но еще важнее было, что он входил в состав AstraLinux SE, «проще с триггерами» бонусом оказалось).

Deleted
()
Ответ на: комментарий от AtomicMan

Если память не изменяет - он внутри себя порождает событие, которое приводит к рекурсивному вызову самого себя.

При «обновить А» вызвать «обновить Б», а при «обновлении Б», опять «обновление А» (точнее - удаление, но, видимо, это одно и тоже для MySQL). Т.е. - он не закончился и таблица заблокирована, когда он еще раз пытается себя же стрельнуть и не может.

Поэтому логика такая, что при «обновить А» - надо дергать промежуточное обновление С и заканчиваться, а изменения уже в С отслеживать другим механизмом, в котором обновление Б повторно будет дергать опосредованно обновление А. Вне контекста первого триггера.

Пардон, за идиотское изложение мысли. Надеюсь более/менее понятно, что пытаюсь сказать. У меня такое было на реальной задаче, и другого способа это обойти я не нашел в MySQL.

Deleted
()
Ответ на: комментарий от Deleted

Собственно, вы правы. В моих двух триггерах не возникает рекурсии, но тем не менее. Обошел через создание дополнительной таблицы и EVENT. Просто каждую минуту дергаю дополнительную таблицу и вызываю процедуру. Ох уж этот убогий MySQL...

AtomicMan
() автор топика
Ответ на: комментарий от AtomicMan

Возможно есть более красивые решения. Но я их не нашел. То приложение имело специфику «закрытого инструмента» со спец. доступом и т.д., из которого надо было публиковать в общий доступ малую часть один раз в месяц. Поэтому EVENT можно было хоть раз в сутки вызывать. Для других целей, возможно, это неприемлемо.

MySQL прекрасен для своих задач. В 9 из 10 случаев. Особенно из-за кэширования результатов запросов на ISAM-образных таблицах. Postgres никогда его не догонит по скорости в простых применениях. Но бизнес-логику худо/бедно сложную переносить в MySQL получается не очень.

Мне так кажется.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.