Для чего нужен триггер в контексте баз данных?

Ответ

Триггер (Trigger) — это специальная хранимая процедура в СУБД, которая автоматически выполняется (срабатывает) при наступлении определенного события с таблицей: INSERT, UPDATE или DELETE. Триггеры привязаны к таблице и позволяют реализовать сложную бизнес-логику и поддержание целостности данных непосредственно на уровне БД.

Типичные сценарии использования:

  1. Аудит и логирование изменений:

    CREATE TRIGGER audit_employee_update
    AFTER UPDATE ON Employees
    FOR EACH ROW
    BEGIN
        INSERT INTO AuditLog (table_name, record_id, action, old_value, new_value, changed_at, changed_by)
        VALUES ('Employees', OLD.id, 'UPDATE', OLD.salary, NEW.salary, CURRENT_TIMESTAMP, USER());
    END;

    Здесь OLD и NEW — псевдонимы для строк до и после изменения.

  2. Поддержание денормализованных данных или вычисляемых полей:

    CREATE TRIGGER update_order_total
    AFTER INSERT ON OrderItems
    FOR EACH ROW
    BEGIN
        UPDATE Orders
        SET total_amount = (
            SELECT SUM(quantity * price) FROM OrderItems WHERE order_id = NEW.order_id
        )
        WHERE id = NEW.order_id;
    END;
  3. Сложная валидация, которую нельзя выразить через CHECK:

    CREATE TRIGGER validate_salary
    BEFORE INSERT ON Employees
    FOR EACH ROW
    BEGIN
        IF (NEW.salary > (SELECT avg_salary * 2 FROM Department WHERE id = NEW.department_id)) THEN
            SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Salary exceeds department limit';
        END IF;
    END;

Важные особенности и недостатки:

  • Прозрачность: Логика в триггерах скрыта от прикладного кода, что может усложнить отладку.
  • Производительность: Каждая операция с таблицей несет дополнительную нагрузку от выполнения триггера.
  • Каскадное срабатывание: Триггер может модифицировать другую таблицу, в которой тоже есть триггер, что может привести к цепочке вызовов.
  • Порядок: В некоторых СУБД можно задавать порядок выполнения нескольких триггеров на одно событие.

Итог: Триггеры — мощный, но требующий осторожного применения инструмент для реализации логики, критичной к целостности данных, непосредственно в БД.

Ответ 18+ 🔞

Слушай, вот объясню тебе про триггеры, как есть. Представь себе, что твоя база данных — это такой склад, а таблицы — это полки. Триггер — это, блядь, злой гном-надзиратель, который привязан к конкретной полке и сидит на ней, не спит. И как только ты пытаешься что-то на этой полке сделать — положить новую коробку (INSERT), переставить старую (UPDATE) или, не дай бог, выкинуть нахуй (DELETE) — этот гном сразу выпрыгивает и начинает свою волшебную хуйню. Автоматически, сам, без твоего ведома. Вот это и есть триггер, ёпта.

Где эта мартышлюшка может пригодиться?

  1. Шпионить за всеми, как стукач. Допустим, кто-то полез в таблицу зарплат (Employees) и поправил себе цифры. А гном-триггер уже тут как тут, всё видит и записывает в отдельную чёрную книжку (AuditLog), кто, когда и сколько украл.

    CREATE TRIGGER audit_employee_update
    AFTER UPDATE ON Employees
    FOR EACH ROW
    BEGIN
        INSERT INTO AuditLog (table_name, record_id, action, old_value, new_value, changed_at, changed_by)
        VALUES ('Employees', OLD.id, 'UPDATE', OLD.salary, NEW.salary, CURRENT_TIMESTAMP, USER());
    END;

    Видишь OLD и NEW? Это как фотки «было» и «стало». Гном их сравнивает и доносит, хитрая жопа.

  2. Поддерживать порядок, потому что все вокруг распиздяи. Добавили новую позицию в заказ (OrderItems)? Ну ясное дело, общая сумма заказа (Orders.total_amount) теперь не бьётся. А гном уже побежал её пересчитать и поправить, чтобы всё было ажуре.

    CREATE TRIGGER update_order_total
    AFTER INSERT ON OrderItems
    FOR EACH ROW
    BEGIN
        UPDATE Orders
        SET total_amount = (
            SELECT SUM(quantity * price) FROM OrderItems WHERE order_id = NEW.order_id
        )
        WHERE id = NEW.order_id;
    END;

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

  3. Быть строгим вышибалой, когда встроенных правил (CHECK) не хватает. Хочет менеджер вписать себе зарплату в два раза выше средней по отделу? Гном-триггер типа BEFORE INSERT его нахуй пошлёт с ошибкой, даже не дав записать эту поебень.

    CREATE TRIGGER validate_salary
    BEFORE INSERT ON Employees
    FOR EACH ROW
    BEGIN
        IF (NEW.salary > (SELECT avg_salary * 2 FROM Department WHERE id = NEW.department_id)) THEN
            SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Salary exceeds department limit';
        END IF;
    END;

Но не всё так гладко, чувак. Есть и подводные ебушки-воробушки:

  • Невидимка. Вся логика спрятана в недрах БД. Смотришь на красивый код приложения app.saveEmployee(), а откуда там берутся логи или почему сумма пересчиталась — нихуя не понятно. Надо лезть в схему базы и искать этого гнома. Доверия ебать ноль к такой системе, если ты её не проектировал.
  • Тормоз. Каждое действие на полке теперь — это не просто действие, а ещё и выступление гнома с хуевой магией. Если триггер тяжелый, то вся система будет ебаться как черепаха.
  • Цепная реакция. Гном из триггера полез что-то поправить в другой таблице. А там сидит ещё один гном, который тоже срабатывает. И понеслась… Может получиться такая каскадная пиздопроебильня, что сервак просто накроется медным тазом.
  • Очередь. Если на одну полку навешано пять гномов на одно событие, то важно, в каком порядке они будут прыгать. А это ещё тот геморрой.

Итог, блядь. Триггеры — это овердохуища мощный инструмент, когда нужно железно гарантировать какое-то правило прямо в базе, чтобы никакой идиотский код приложения не мог его обойти. Но юзать их нужно с умом, а то получится манда с ушами: вроде логика есть, а разобраться, кто и где срабатывает, — нихуя невозможно. Э, бошка, думай, прежде чем плодить этих невидимых гномов.