MySQL中需用TIMESTAMP或DATETIME类型配合DEFAULT CURRENT_TIMESTAMP设创建时间,5.6.5+才支持DATETIME;设双时间戳时created_at用DEFAULT CURRENT_TIMESTAMP,updated_at须加NOT NULL和ON UPDATE CURRENT_TIMESTAMP。

MySQL建表时用DEFAULT CURRENT_TIMESTAMP设置创建时间
直接在 CREATE TABLE 语句里给 DATETIME 或 TIMESTAMP 字段加 DEFAULT CURRENT_TIMESTAMP 就能自动填入插入时刻的时间戳,但必须注意字段类型和 MySQL 版本限制。
常见错误是把 INT 或 BIGINT 类型字段也这么写,结果报错 Invalid default value for 'xxx' —— 因为只有 TIMESTAMP 和 DATETIME 支持该默认值。
-
TIMESTAMP字段默认带时区转换(存 UTC,查本地时区),且范围小(1970–2038);DATETIME不做时区转换,范围大(1000–9999),MySQL 5.6.5+ 才支持其DEFAULT CURRENT_TIMESTAMP - 如果字段允许
NULL,DEFAULT CURRENT_TIMESTAMP仍生效;但如果显式插入NULL,则存入NULL而非当前时间 - 一个表里最多只能有一个
TIMESTAMP字段能用CURRENT_TIMESTAMP做默认值(旧版本限制,5.6.5+ 已放宽,但多个TIMESTAMP字段都设默认值时需显式加NULL或NOT NULL消除歧义)
CREATE TABLE logs ( id INT PRIMARY KEY AUTO_INCREMENT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
如何同时设置创建时间和更新时间(两个时间戳字段)
想让 created_at 记插入时间、updated_at 记最后修改时间,不能两个都只写 DEFAULT CURRENT_TIMESTAMP —— 否则 MySQL 会报错 Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause(5.6.5 之前严格限制,之后放宽但仍有隐含约束)。
关键点在于:第二个字段必须显式声明为 NOT NULL,且用 ON UPDATE CURRENT_TIMESTAMP 触发更新,而第一个用 DEFAULT CURRENT_TIMESTAMP 即可。
- 推荐组合:
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP+updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP - 如果用
DATETIME,MySQL 5.6.5+ 才支持两者同时存在;低于此版本只能用TIMESTAMP,且第二个字段必须加ON UPDATE CURRENT_TIMESTAMP,否则不自动更新 -
ON UPDATE CURRENT_TIMESTAMP只在整行被UPDATE且该字段未出现在SET子句中时才触发;如果 SQL 显式写了SET updated_at = ...,就不会覆盖
ALTER TABLE时添加DEFAULT CURRENT_TIMESTAMP失败的常见原因
执行 ALTER TABLE xxx ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 报错 Invalid default value for 'created_at',大概率是因为表里已有数据,而该字段没指定 NOT NULL 且无默认值,MySQL 无法为老记录填充值。
- 解决方案:先加字段并设
NULL,再用UPDATE补老数据,最后改NOT NULL并加默认值 - 或一步到位:
ALTER TABLE xxx ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP—— 这要求表为空,或 MySQL 严格模式关闭(不推荐) - 注意
sql_mode:若启用了STRICT_TRANS_TABLES,对空值和默认值校验更严,容易在此处失败
PHP/Python等应用写入时绕过DEFAULT CURRENT_TIMESTAMP的后果
如果代码里显式给 created_at 字段传了 NULL 或空字符串,MySQL 会按字面量处理,不会回退到默认值 —— 结果可能是 NULL(字段允许空)、'0000-00-00 00:00:00'(非严格模式),或直接报错(严格模式下非法日期)。
- 安全做法:插入时不提这个字段,让数据库自己填;或者传合法时间字符串如
'2024-05-20 14:30:00' - ORM 如 Laravel Eloquent、Django ORM 默认不传
created_at,但有些手写 SQL 或低配 ORM 会拼全字段,容易踩坑 - 测试时可故意插入
NULL看是否报错,确认表定义和 SQL 模式是否匹配
真正容易被忽略的是时区。即使你用了 TIMESTAMP,如果应用连接时没设 time_zone='+00:00',而服务器时区是 CST,那插入和查询看到的时间可能差 8 小时 —— 这不是默认值的问题,而是时区链路没对齐。


















