必须用AFTER INSERT,因BEFORE阶段自增主键未生成,NEW.id为NULL,导致审计表插入失败;且审计表字段顺序、类型、字符集须与源表严格一致,否则会错位、截断或报错。
能,但必须用 AFTER INSERT,且审计表字段顺序、类型、字符集要和源表严格一致;否则写入会错位、截断甚至报错。
BEFORE INSERT 同步到审计表?因为 BEFORE INSERT 时主表记录尚未落盘,自增主键(如 id)可能还没生成。你往审计表里插 NEW.id,结果是 NULL 或默认值,导致数据不一致。
NEW.id 在 BEFORE 阶段对自增列不可靠,除非显式赋值AFTER INSERT 才能确保 NEW 包含完整、已确认的行数据BEFORE 访问 NEW,但同步场景仍推荐 AFTER,避免逻辑混淆INSERT INTO audit SELECT NEW.* 为什么经常失败?表面简洁,实则埋雷:一旦审计表比源表多字段(比如加了 op_type、op_time),或字段顺序不一致,这条语句立刻报错 Column count doesn't match value count。
INSERT INTO audit (id, name, op_type, op_time) VALUES (NEW.id, NEW.name, 'INSERT', CURRENT_TIMESTAMP)
Illegal mix of collations,尤其当源表用 utf8mb4_unicode_ci、审计表用 utf8mb4_general_ci 时NOT NULL 字段但没在 VALUES 中提供值,直接插入失败CURRENT_USER() 返回的是 [email protected].% 这类连接账号,对业务审计毫无意义。真实操作人必须由应用层带入。
SET @current_app_user = 12345;
op_user = @current_app_user(注意:不能在 BEFORE 里用 := 赋值给 NEW,除非审计表字段与源表完全一致)USER() 或 SYSTEM_USER(),它们反映的是 TCP 连接身份,不是业务主体INSERT /* user_id=12345 */ INTO orders...),但触发器无法解析——得靠 ProxySQL 或应用日志兜底会,而且非常明显。触发器是同步阻塞执行的,主表 INSERT 必须等审计写完才返回。一个慢查询、一个锁等待、一个跨库写入,都会卡住业务。
(op_time, table_name)
UUID()、JSON_OBJECT() 等函数,MySQL 5.7 不支持,8.0 支持但性能损耗高binlog 异步补全真正麻烦的不是语法,而是字段一致性、时区对齐、操作人透传这三个点——漏掉任何一个,日志就不可信;而性能问题往往上线后才暴露,那时再切架构代价已经很大。