[特殊字符] MySQL 报错 Invalid default value?罪魁祸首是 NO_ZERO_DATE 和 NO_ZERO_IN_DATE
明白了!你希望专门针对 NO_ZERO_DATE 和 NO_ZERO_IN_DATE 这两个 SQL 模式引发的问题,写一篇聚焦、清晰的博客总结。下面是一篇精炼、专业、直击痛点的博客文章,专讲这两个选项的问题与解决方案,适合开发者快速理解并解决问题。
🚫 MySQL 报错 Invalid default value?罪魁祸首是 NO_ZERO_DATE 和 NO_ZERO_IN_DATE
关键词:MySQL、NO_ZERO_DATE、NO_ZERO_IN_DATE、Error 1067、GORM、Django、ORM、sql_mode、零日期
🔥 问题重现
你在本地开发时,程序(如 GORM、Django、Laravel 等)自动建表失败,报错:
Error 1067 (42000): Invalid default value for ‘created_at’
或
Incorrect datetime value: ‘0000-00-00 00:00:00’
但代码里明明没写 ‘0000-00-00’!这是怎么回事?
🕵️♂️ 真相:MySQL 的“零日期”限制
从 MySQL 5.7 开始,默认 sql_mode 包含两个严格限制:
模式 作用
NO_ZERO_DATE 禁止使用 ‘0000-00-00’ 作为合法日期
NO_ZERO_IN_DATE 禁止使用 ‘2025-00-01’、‘2025-12-00’ 等“部分为零”的日期
✅ 合法日期:‘2025-12-01’
❌ 被 NO_ZERO_DATE 拒绝:‘0000-00-00’
❌ 被 NO_ZERO_IN_DATE 拒绝:‘2025-00-01’
❓ 为什么我的代码会触发这个错误?
很多 ORM(如 GORM)在以下情况会“隐式”使用零日期:
-
字段定义为 NOT NULL,但未指定默认值
→ MySQL 尝试用 ‘0000-00-00 00:00:00’ 填充 → 被拒绝 -
旧版 ORM 默认行为
→ 假设 ‘0000-00-00’ 是“空值”的合法表示(这是 MySQL 5.5 时代的遗留) -
迁移脚本未适配严格模式
✅ 解决方案(二选一)
✅ 方案一:【快速修复】关闭限制(仅限本地开发)
编辑 MySQL 配置文件(如 my.ini):
ini
[mysqld]
sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
⚠️ 注意:去掉了 NO_ZERO_DATE 和 NO_ZERO_IN_DATE
然后 重启 MySQL,验证:
sql
SELECT @@sql_mode;
– 确保输出中不含这两个选项
✅ 优点:立即生效,无需改代码
❌ 缺点:掩盖问题,绝不适用于生产环境
✅ 方案二:【根本解决】规范字段定义(推荐!)
让代码主动适配严格模式,这才是专业做法。
▶ GORM 示例(Go)
go
type User struct {
ID uint gorm:“primarykey”
Name string
CreatedAt time.Time gorm:“type:timestamp;not null;default:CURRENT_TIMESTAMP”
UpdatedAt time.Time gorm:“type:timestamp;not null;default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP”
}
▶ Django 示例(Python)
在 settings.py 中确保:
python
USE_TZ = True # 使用时区感知时间
并在模型中避免手动设置零值。
▶ 通用原则
用 NULL 表示“无日期”,而不是 ‘0000-00-00’
显式设置默认值:DEFAULT CURRENT_TIMESTAMP
避免 DATETIME NOT NULL 无默认值
🧠 为什么 MySQL 要禁止零日期?
‘0000-00-00’ 不是合法的 ISO 8601 日期
容易导致:
时间计算错误(如 DATEDIFF 返回负数)
应用逻辑混乱(无法区分“未填写”和“真实日期”)
数据库迁移失败(PostgreSQL、SQL Server 不支持)
✅ 保持 NO_ZERO_DATE 开启,是数据质量的第一道防线
📌 总结
场景 建议
本地快速调试 临时关闭 NO_ZERO_DATE / NO_ZERO_IN_DATE
长期开发 / 生产环境 保持开启,修复代码,使用合法时间值
最佳实践 用 CURRENT_TIMESTAMP 或 NULL,杜绝零日期
💡 真正的高手,不是绕过限制,而是让代码在限制下依然优雅运行。
🔗 延伸阅读
MySQL 5.7 sql_mode 官方文档
Why does MySQL disallow zero dates?
希望这篇聚焦 NO_ZERO_DATE 和 NO_ZERO_IN_DATE 的总结能帮你彻底理解并解决这个问题!欢迎分享给同样踩坑的小伙伴 💡
