Laravel迁移报SQL默认值错误,但手动执行SQL正常
多非nullable Timestamp字段在MariaDB 5.5.x下的Laravel迁移报错解析
底层原因
MariaDB 5.5(及同版本线的MySQL)对TIMESTAMP类型存在历史限制:
- 单表中最多仅能有一个非nullable且无显式默认值的
TIMESTAMP字段,该字段会被自动赋予DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP属性。 - 当尝试创建第二个这类
TIMESTAMP字段时,数据库因无法生成合法默认值,再结合你的SQL_MODE中开启的NO_ZERO_DATE和NO_ZERO_IN_DATE规则,直接抛出1067 Invalid default value错误。
直接执行SQL无报错的原因
Laravel迁移执行与手动执行SQL的逻辑存在差异:
- 通过
php artisan migrate执行时,Schema Builder会隐式尝试为非nullable的TIMESTAMP字段设置默认值,而老版本MariaDB不支持多字段的这种自动处理,引发冲突。 - 手动执行生成的SQL时,语句未显式指定默认值,数据库此时的解析逻辑会绕过该限制,但实际上这个表结构在严格模式下存在隐患——插入数据时若未指定
send_after和send_before的值,仍会报错。
DateTime类型正常的原因
DATETIME类型从不存在TIMESTAMP的“单字段默认值绑定”限制,它不会自动生成默认值,只要插入时提供合法日期值,就不会触发SQL_MODE的相关限制。
解决方案
有以下几种可行处理方式:
- 显式指定默认值:修改迁移代码,为非nullable的
TIMESTAMP字段设置合法默认值,比如使用当前时间:
也可根据业务需求设置其他固定默认值。$table->timestamp('send_after')->index()->useCurrent(); $table->timestamp('send_before')->index()->useCurrent(); - 改用DateTime类型:若不需要
TIMESTAMP的自动更新特性,直接替换为datetime类型:$table->dateTime('send_after')->index(); $table->dateTime('send_before')->index(); - 调整SQL_MODE(不推荐):临时移除
NO_ZERO_DATE和NO_ZERO_IN_DATE模式,但这会降低数据严格性,可能引入无效日期值,生产环境不建议使用。
内容的提问来源于stack exchange,提问作者Yevgen
相关产品推荐
相关产品推荐

