必须配合会话变量或应用层透传才能准确定义“谁改了数据”,因user()和current_user()返回的是连接账号而非真实操作人,触发器中需用ifnull(@app_user, user())回退获取。

不能只靠触发器自动“猜出”用户是谁——USER() 和 CURRENT_USER() 返回的不是真实操作人,而是连接账号或定义者,必须配合会话变量或应用层透传才能准确定义“谁改了数据”。
触发器里怎么拿到真实用户和客户端信息
MySQL 的 USER() 返回的是 username@hostname,但连接池、ProxySQL 或 ORM 批量操作会让它固定为 pool_user@localhost;PostgreSQL 的 session_user 是认证用户,比 current_user 更可靠;SQL Server 需用 ORIGINAL_LOGIN() 而非 SUSER_SNAME()。
- MySQL 8.0+ 可在应用连接后立刻执行
SET @app_user = 'u123';,触发器中用IFNULL(@app_user, USER())回退 - PostgreSQL 推荐用
current_setting('app.user_id', true),前提是应用先执行SET app.user_id = 'u123' - 所有数据库都应额外记录
inet_client_addr()(PG)、CONNECTIONPROPERTY('client_net_address')(SQL Server)或HOST_NAME()(SQL Server),但注意空值处理 - 别在触发器里写
SELECT USER()—— 触发器不允许显式查询,直接调函数即可
INSERT/UPDATE/DELETE 触发器必须分开写,且时机不能错
一个触发器不能响应多种操作类型,混用 BEFORE/AFTER 会导致 OLD 或 NEW 不可用,日志字段全为 NULL。
-
DELETE必须用BEFORE DELETE才能读到OLD.*;AFTER DELETE中OLD已不可见 -
UPDATE用AFTER UPDATE,可同时访问OLD.column_name和NEW.column_name -
INSERT只有NEW,必须用AFTER INSERT(BEFORE INSERT中NEW尚未完成赋值,某些字段可能为空) - MySQL 里漏写
DELIMITER //和结尾//,整个触发器创建会静默失败
audit_log 表字段设计不当,日志就等于没记
字段类型不匹配、长度不足、缺少索引,会导致写入失败却不报错,或者查不出东西。
-
old_data和new_data必须用JSON类型(MySQL 5.7+/PG),别用TEXT—— 后者无法用->'$.status'做高效过滤 -
table_name至少VARCHAR(64),operation_type用ENUM('INSERT','UPDATE','DELETE')或VARCHAR(10),别用CHAR(1) - 必须加联合索引:
INDEX idx_table_time (table_name, created_at),否则按表查日志就是全表扫描 - IP 字段别设
CHAR(15),IPv6 地址最长 45 字符,MySQL 用VARCHAR(45),PostgreSQL 用INET类型并配NULLIF(inet_client_addr(), '0.0.0.0')
别让触发器拖垮主业务——轻量是唯一原则
触发器运行在主事务上下文中,任何耗时操作都会卡住业务 SQL,且失败即回滚。
- 禁止在触发器里调用存储过程、UDF、HTTP 接口、跨库写入、
SELECT COUNT(*)等任何非单行 INSERT 操作 - 大字段(如
TEXT、BLOB)不要原样进日志,用JSON_OBJECT('id', NEW.id, 'summary', LEFT(NEW.content, 1024))截断 - UPDATE 触发器要判断字段是否真变了:MySQL 用
IF OLD.status != NEW.status THEN ...,避免无意义日志刷屏 - PostgreSQL 建议把
audit_log设为UNLOGGED,提速 3–5 倍,审计场景可接受崩溃丢失(日志本就用于事后分析)
最常被忽略的一点:触发器对批量操作(比如 UPDATE users SET status=2 WHERE id IN (1,2,3,...1000))只触发一次,但 OLD/NEW 在 MySQL 中仅返回单行——这意味着你看到的只是其中一条的变更,其余 999 条没记录。真要全覆盖,得用 MySQL 8.0+ 的 AFTER STATEMENT 触发器,或改由应用层基于 binlog 解析补全。











