mysql触发器中应优先使用current_timestamp而非now(),因其符合sql标准、语义更清晰,且避免绕过表定义的默认行为;需通过set new.updated_at = current_timestamp赋值,不可用update语句以防递归。

MySQL触发器里用NOW()还是CURRENT_TIMESTAMP?
触发器中更新时间字段,NOW() 和 CURRENT_TIMESTAMP 在绝大多数场景下行为一致,但严格来说,CURRENT_TIMESTAMP 是 SQL 标准语法,且在定义列默认值时更常见;而 NOW() 是 MySQL 的同义函数。两者都返回当前事务开始时的时间戳(非实时秒级变化),这点很重要——如果你在一个长事务里多次触发更新,得到的仍是同一时间点。
- 触发器内优先写
CURRENT_TIMESTAMP,语义更清晰,也方便后续迁移到其他兼容标准的数据库(如 MariaDB) - 不要用
SYSDATE(),它返回的是函数执行时刻的真实系统时间,会导致同一事务内多次触发产生不同时间,破坏数据一致性 - 如果表本身已有
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,再在触发器里重复赋值会冲突,必须去掉该列的ON UPDATE子句
UPDATE触发器里如何避免无限递归?
MySQL 默认允许触发器修改本表,但若触发器内执行了 UPDATE 当前表,又恰好命中了同一触发器的触发条件,就会无限递归,最终报错:ERROR 1442 (HY000): Can't update table 'xxx' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
- 绝对不要在
BEFORE UPDATE触发器里写UPDATE xxx SET ...操作本表 - 正确做法是直接给
NEW.updated_at赋值:SET NEW.updated_at = CURRENT_TIMESTAMP; - 如果业务逻辑复杂(比如要根据其他字段联动更新),也必须通过修改
NEW的字段完成,而不是发一条新UPDATE语句 - 注意:只有
BEFORE触发器能修改NEW值;AFTER触发器只能读,不能改,此时再想更新已无意义
INSERT和UPDATE共用一个触发器?别这么做
有人试图用一个 BEFORE INSERT OR UPDATE 触发器(MySQL 不支持这种语法)来统一处理时间字段,但 MySQL 要求每个触发器必须明确指定单一事件类型:BEFORE INSERT、BEFORE UPDATE、AFTER INSERT 等。
- 必须分别创建两个触发器:一个用于插入时初始化
created_at和updated_at,另一个用于更新时仅刷新updated_at - 插入触发器中,
NEW.created_at和NEW.updated_at都应设为CURRENT_TIMESTAMP,除非业务要求created_at来自应用层传入 - 更新触发器中,只动
NEW.updated_at,不动NEW.created_at,否则可能覆盖原始创建时间
触发器没生效?检查这三处硬性限制
触发器不执行往往不是逻辑问题,而是被 MySQL 的隐式规则拦住了:
- 表引擎必须是
InnoDB或MyISAM;MEMORY、CSV等引擎不支持触发器 - 用户权限需包含
TRIGGER权限,仅SELECT/INSERT/UPDATE不够 - MySQL 5.7+ 默认开启
sql_mode中的STRICT_TRANS_TABLES,如果触发器里对非空字段赋了NULL,整个语句会失败并回滚,看起来像“没触发”
另外,触发器不会响应通过 LOAD DATA INFILE 或分区 TRUNCATE 等批量操作,这些场景需要额外补全时间字段逻辑。
触发器看似简单,但时间字段的语义边界(创建 vs 更新)、事务快照行为、引擎与权限依赖,哪一环松动都会让自动维护失效。真正稳的方案,往往是在应用层加一层校验,而不是全盘交给触发器。











