数据库触发器无法直接获取真实业务用户,必须由应用层显式传参(如mysql设@current_operator、postgresql用current_setting('app.user_id', true)),否则current_user()等仅返回连接账号。

不能直接记录真实业务用户,CURRENT_USER()、USER()、SESSION_USER() 都只返回数据库连接账号,不是你系统里登录的张三或李四。
为什么 CURRENT_USER() 在触发器里总是显示同一个账号
因为它是认证用户——即应用用哪个账号连上数据库,它就返回那个。比如 Web 应用统一用 webapp@localhost 连接池,所有触发器日志都会写这个,根本分不清操作人。
-
CURRENT_USER()返回权限主体(认证账号),USER()返回连接声明(含 IP),两者在普通部署下几乎一样 - 代理用户(proxy user)机制极少启用,
CURRENT_USER()在这种场景才有区分度,但绝大多数业务不走这条路 - 触发器无法访问 HTTP header、JWT、session ID 等应用层上下文,数据库本身不保存这些信息
MySQL 触发器里怎么拿到真实操作人
靠应用层显式传值,用会话变量中转,触发器读取并兜底。
- 应用每次执行 DML 前必须先执行:
SET @current_operator = 'u_12345'; - 触发器中不能直接
SELECT @current_operator,只能直接引用:@current_operator - 务必判空:
IF @current_operator IS NOT NULL THEN ... ELSE CURRENT_USER() END IF - 变量作用域仅限当前连接,连接池复用时不会污染,但漏设就会是
NULL—— 日志里出现大量NULL或unknown,基本就是应用没统一加SET
PostgreSQL 怎么做更可靠
用 current_setting('app.user_id', true) 读自定义配置项,比 MySQL 的会话变量更规范。
- 应用需提前执行:
SET app.user_id = 'u_789'; - 数据库必须声明该配置项:
ALTER DATABASE mydb SET app.user_id = '';,否则调用会报错 - 第二个参数
true很关键:找不到时不报错,返回NULL,避免触发器中断 - 建议始终包裹:
COALESCE(current_setting('app.user_id', true), 'unknown')
真正麻烦的不是语法,而是应用层是否每次请求都严格设置、是否所有入口(包括脚本、DBA 直连、定时任务)都被覆盖。漏掉任意一环,审计日志就断档。这不是数据库能自动补全的事。











