MySQL 5.6.5 之前 DATETIME 不支持 CURRENT_TIMESTAMP,默认值会报错 ERROR 1067;5.6.5–7.9 仅支持 DEFAULT CURRENT_TIMESTAMP,ON UPDATE 被静默忽略;8.0+ 才完整支持 DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP。

MySQL 5.6.5 之前,DATETIME 根本不支持 CURRENT_TIMESTAMP 作为默认值或更新值——这不是你写错了,是版本不认。
DATETIME 的 DEFAULT CURRENT_TIMESTAMP 在不同 MySQL 版本中是否有效?
只看版本号:低于 5.6.5 的 MySQL,DATETIME 字段声明 DEFAULT CURRENT_TIMESTAMP 会直接报错 ERROR 1067 (42000): Invalid default value for 'xxx'。这是硬性限制,没有绕过方式。
-
5.6.5 ≤ MySQL < 8.0:支持DEFAULT CURRENT_TIMESTAMP,但 不支持ON UPDATE CURRENT_TIMESTAMP(哪怕写了也静默忽略) - MySQL 8.0+:
DATETIME才真正支持DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,且允许多个字段同时使用该语法 - 如果你用的是 MySQL 5.7,别挣扎了——
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP永远不会生效
为什么 SHOW CREATE TABLE 显示了 ON UPDATE 但实际不触发?
常见现象:执行了 ALTER TABLE t MODIFY updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP,再查 SHOW CREATE TABLE t 确实看到该子句,但 UPDATE 后字段值纹丝不动。
- 根本原因:MySQL 解析时“记下了”,但执行时发现类型不支持,就跳过自动更新逻辑,也不报错
- 更隐蔽的坑:
ORM(如 Laravel Eloquent、MyBatis)生成的UPDATE语句如果显式包含updated_at = ?,哪怕值是NULL或旧值,MySQL 都视为“用户赋值”,直接禁用ON UPDATE - 验证方法:用纯 SQL 手动执行
UPDATE t SET name='x' WHERE id=1(不带updated_at字段),再观察是否变化
timestamp 字段 ON UPDATE 不生效的典型配置错误
很多人以为只要类型是 TIMESTAMP 就能自动更新,结果发现插入后第一次更新就没反应——大概率是建表时漏掉了关键组合。
- 必须同时声明
DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP,缺一不可;只写一个,行为完全不同 - 如果表里已有多个
TIMESTAMP字段,MySQL 只允许第一个有DEFAULT CURRENT_TIMESTAMP(5.6.5+ 规则),其余字段即使加了也会被忽略 -
sql_mode中若含NO_ZERO_DATE或STRICT_TRANS_TABLES,而字段定义为TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP,可能因默认值非法导致整个ON UPDATE失效
如何安全地让更新时间字段真正自动刷新?
别赌版本兼容性,也别依赖 ORM 的“聪明”。最稳的路径是明确选型 + 显式约束:
- 线上环境 MySQL < 8.0:统一用
TIMESTAMP类型,且首字段定义为updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP - MySQL 8.0+:可用
DATETIME,但务必确认sql_mode不含NO_ZERO_DATE,且建表语句完整写出两个子句 - 任何版本下,都避免在应用层 UPDATE 语句中手动设置时间字段;如果 ORM 强制传参,改用触发器兜底(但注意性能开销)
- 上线前必做:用
SELECT NOW(), SLEEP(1), NOW()确认服务器时区与应用一致,否则CURRENT_TIMESTAMP表现会“错位”
最容易被忽略的一点:MySQL 对 TIMESTAMP 的自动行为,本质是“仅当该字段未出现在 SET 子句中时才介入”。哪怕 ORM 传了个 NULL 或空字符串,它也算“显式赋值”——自动更新就此失效。


















