MySQL 5.7+ 中 CURRENT_TIMESTAMP 默认值不生效,主因是 SQL mode(如 STRICT_TRANS_TABLES)导致隐式默认被拒绝,或 ORM 显式传 NULL 覆盖数据库逻辑,而非版本或语法错误。
MySQL 5.7+ 中 CURRENT_TIMESTAMP 默认值不生效的典型表现
插入数据时直接报错 field 'update_time' doesn't have a default value,或字段写入为 '0000-00-00 00:00:00'(尤其在严格模式关闭时),但你明明在建表语句里写了 default current_timestamp on update current_timestamp。
- 本地开发环境正常,线上 CentOS 7.4 + MySQL 5.7 环境却失效 —— 这大概率不是 SQL 写错了,而是 SQL mode 或服务器配置在捣鬼
- Spring Boot 实体类中若手动给
updateTime赋了null或未初始化值,MyBatis 会把NULL显式传入 SQL,覆盖数据库默认逻辑 - 使用
INSERT ... SELECT或批量插入时,部分驱动/框架可能忽略字段默认行为,尤其当列未显式列出
检查 sql_mode 是否禁用了时间戳自动填充
MySQL 5.7 默认启用了 STRICT_TRANS_TABLES 和 NO_ZERO_DATE,但真正影响 CURRENT_TIMESTAMP 默认值生效的是 NO_AUTO_VALUE_ON_ZERO —— 它不相关;真正关键的是:是否启用了 TRADITIONAL 模式子集中的 STRICT_ALL_TABLES,以及更隐蔽的 ALLOW_INVALID_DATES 缺失导致解析失败。
- 执行
SELECT @@sql_mode;,确认结果中不含NO_ENGINE_SUBSTITUTION(它本身不干扰时间戳,但常伴随其他限制) - 重点看是否有
STRICT_TRANS_TABLES:它会让 MySQL 拒绝隐式默认值(如未提供字段又无 DEFAULT 的情况),但对已声明CURRENT_TIMESTAMP的字段本不该拦截——除非你的 INSERT 语句显式写了update_time = NULL - 临时验证:执行
SET sql_mode = '';后重试插入,若成功,说明是模式限制;但生产环境切勿长期关闭,应定位具体冲突项
权限与回滚场景下时间戳被清空的真相
不是“权限不够导致无法写入”,而是事务回滚后字段值恢复为初始状态 —— 如果你用的是 INSERT 后立刻 UPDATE 修改同一行,而 update_time 字段没参与 UPDATE SET 子句,它就不会被更新;如果事务中途回滚,那连第一次的 INSERT 都没落库,自然谈不上时间戳。
- 检查应用层是否在 insert 后立即执行了 update 但漏掉了
update_time字段赋值(例如 JPA 中只改了status,没设updateTime = LocalDateTime.now()) - 确认数据库用户对目标表有
INSERT和UPDATE权限 —— 缺少UPDATE权限时,ON UPDATE CURRENT_TIMESTAMP不会触发,但INSERT仍可走DEFAULT;不过若应用误判为“更新失败”而重试,就可能引发混乱 - 回滚本身不会“清空时间戳”,但如果你在事务内先
INSERT(此时create_time和update_time都被设为当前时间),再UPDATE某字段但没碰update_time,最后回滚,那整条记录根本不存在,也就没有“被清空”的时间戳
MyBatis-Plus 或 JPA 场景下,自动填充和数据库默认值的冲突
两者同时存在时,不是“谁优先”,而是“谁先出手”——如果 ORM 框架在拼 SQL 时把 update_time 当作普通字段显式传了 NULL 或空值,数据库的 DEFAULT 就彻底失效。
- 检查实体类中
updateTime字段是否被@TableField(fill = FieldFill.INSERT_UPDATE)正确标注,且MetaObjectHandler已被 Spring 扫描并加载 - 查看日志中实际执行的 SQL:如果 INSERT 语句里出现了
update_time = ?且参数是null,那就是框架覆盖了数据库逻辑 - 解决方案二选一:关掉 ORM 的自动填充,完全依赖数据库(确保所有 INSERT 都不显式传该字段);或关掉数据库的
ON UPDATE,只留DEFAULT CURRENT_TIMESTAMP,然后靠 ORM 在 update 时统一注入
最容易被忽略的一点:MySQL 5.6 及以前不支持多个 CURRENT_TIMESTAMP 字段;5.6.5+ 虽支持,但第一个必须是 DEFAULT CURRENT_TIMESTAMP,第二个才可设为 ON UPDATE CURRENT_TIMESTAMP。如果建表顺序反了,或者用了低版本兼容语法,就会静默降级为 0 值。

















