На какие действия можно повесить триггер
Что проверяют
Знаете ли вы триггеры шире, чем «на вставку, обновление и удаление», и понимаете ли, чем они опасны для кода на Go, который про них ничего не знает. Следом обычно спрашивают, где вы бы поставили триггер, а где оставили бы логику в сервисе.
Как отвечать
Раз стек Go, чаще всего речь про PostgreSQL. Там триггер описывается по трём осям:
- событие:
INSERT,UPDATE,DELETEиTRUNCATE. ДляUPDATEможно сузить срабатывание до колонок:UPDATE OF status; - момент:
BEFORE(можно поправитьNEWили отменить операцию),AFTER(строка уже записана, удобно для аудита),INSTEAD OF(только для представлений); - гранулярность:
FOR EACH ROWна каждую строку илиFOR EACH STATEMENTодин раз на весь запрос. УсловиеWHENотсекает лишние срабатывания ещё до вызова функции.
Отдельно стоят событийные триггеры (CREATE EVENT TRIGGER) на DDL: ddl_command_start, ddl_command_end, sql_drop, table_rewrite, а с PostgreSQL 17 ещё и login. Ими, например, запрещают DROP TABLE на проде.
В MySQL выбор уже: только INSERT, UPDATE, DELETE, моменты BEFORE и AFTER, и только построчно.
Со стороны Go полезно сказать, как триггеры живут в проекте: создаются миграциями (goose, golang-migrate) и лежат в репозитории, а значения, выставленные триггером, приложение получает через RETURNING. Типичные удачные применения: updated_at, журнал изменений, pg_notify из триггера, который сервис слушает через WaitForNotification в pgx.
Где спотыкаются
Называют SELECT среди событий. Триггеров на чтение в PostgreSQL нет, для контроля доступа к строкам есть RLS.
Забывают, что TRUNCATE не вызывает триггеры на DELETE. Аудит удалений, построенный только на DELETE, молча пропустит очистку таблицы.
Вешают построчный триггер с тяжёлой логикой и удивляются, что пакетный UPDATE на миллион строк идёт в разы дольше. К тому же логика в триггере не видна при чтении Go-кода и не проверяется юнит-тестами с моками базы.