Будет ли триггер работать при SELECT
Что проверяют
Знаете ли вы, на какие события вообще бывают триггеры, и понимаете ли, что аудит чтения делается другими средствами. Следом часто спрашивают, как тогда залогировать, кто читал таблицу, и чем плоха бизнес-логика в триггерах для Go-сервиса.
Как отвечать
Короткий ответ: нет. В PostgreSQL, MySQL и SQL Server DML-триггеры срабатывают на INSERT, UPDATE, DELETE, в PostgreSQL ещё на TRUNCATE. События SELECT среди них нет: чтение не меняет данные, и привязать к нему триггер нельзя.
Дальше покажите, что знаете оговорки:
- функция внутри SELECT:
SELECT create_order(...)сам триггер не вызывает, но если функция делаетINSERT, сработают триггеры той таблицы. Со стороны это похоже на «триггер на селекте»; SELECT ... FOR UPDATE: блокирует строки, но триггеры не запускает;- представления: в PostgreSQL на view вешают
INSTEAD OFтриггеры, но тоже только для записи; - event triggers: в PostgreSQL реагируют на DDL (
CREATE,ALTER,DROP), не на чтение.
Если нужен аудит чтения, называйте реальные инструменты: расширение pgaudit в PostgreSQL, Fine-Grained Auditing (DBMS_FGA) в Oracle, SQL Server Audit. Либо логирование на уровне приложения.
Для Go второй вариант обычно практичнее: обёртка над репозиторием или хук драйвера. В pgx v5 есть интерфейс QueryTracer, через который пишутся запрос, аргументы и длительность, а идентификатор пользователя берётся из context.Context. Так аудит видит пользователя приложения, а не общую роль пула соединений.
Где спотыкаются
Говорят «да, есть триггер AFTER SELECT» по аналогии с AFTER INSERT. Такого синтаксиса нет ни в одной из популярных СУБД.
Предлагают для аудита хранимую процедуру, которую «все будут вызывать». Любой прямой SELECT её обходит, гарантии нет.
Не учитывают, что Go-сервис ходит в базу под одной ролью пула. Даже pgaudit запишет роль приложения, а не того, кто открыл страницу, поэтому пользователя аудит увидит, только если сервис передаёт его явно, и проще всего это делать в самом сервисе.