Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як працюють тригери в MySQL і які в них обмеження?

Тригер - SQL-код, який MySQL виконує автоматично до чи після INSERT, UPDATE або DELETE для кожного рядка.

DELIMITER //
CREATE TRIGGER orders_audit
AFTER UPDATE ON orders
FOR EACH ROW
BEGIN
    IF NOT (OLD.status <=> NEW.status) THEN
        INSERT INTO order_status_log (order_id, old_status, new_status, changed_at)
        VALUES (NEW.id, OLD.status, NEW.status, NOW());
    END IF;
END //
DELIMITER ;
  • OLD - рядок до зміни (у UPDATE і DELETE), NEW - після (у INSERT і UPDATE);
  • у тригері BEFORE можна змінити значення: SET NEW.slug = LOWER(NEW.slug);
  • SIGNAL SQLSTATE '45000' у BEFORE-тригері скасовує операцію з помилкою.

Обмеження MySQL, які варто знати:

  • лише рядкові тригери (FOR EACH ROW) - тригерів рівня оператора, як у PostgreSQL, немає. Масовий UPDATE мільйона рядків - мільйон викликів;
  • не можна змінювати ту саму таблицю, на яку спрацював тригер (і будь-яку таблицю, яку вже читає оператор, що його викликав) - помилка Can't update table ... in stored function/trigger;
  • тригери не спрацьовують на дії зовнішніх ключів: ON DELETE CASCADE видалить дочірні рядки без їхніх тригерів;
  • кілька тригерів на одну подію дозволені, порядок задають FOLLOWS / PRECEDES;
  • реплікація: з рядковим форматом бінарного журналу (за замовчуванням) на репліці тригери не виконуються - туди приходять уже готові зміни рядків, включно з тими, що зробив тригер на джерелі. Зі STATEMENT-форматом тригери виконуються на репліці знову.

Тригер чи подія Eloquent:

Тригер Подія моделі Eloquent
спрацьовує при масовому update(), сирому SQL, зміні з іншого сервісу так ні
видно в коді застосунку ні так
тестування на справжній базі звичайними тестами
може надіслати лист, поставити завдання в чергу ні так

Підводні камені: невидима логіка (розробник не знає, що UPDATE змінює ще одну таблицю), складність налагодження, додаткові блокування в довгих транзакціях. Тригери мають бути задокументовані, мати зрозумілі назви й створюватися в міграціях (DB::unprepared()), а тести - запускатися на MySQL, а не SQLite.

Правило: у тригерах - інваріанти й аудит, які мають працювати незалежно від того, хто пише в базу; побічні ефекти - у застосунку.

Докладніше в документації: MySQL: синтаксис тригерів

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання