Laravel迁移中default()是否生效取决于数据库驱动:MySQL对TEXT/JSON等类型静默忽略,PostgreSQL允许NULL字段设默认值但需注意冲突,SQLite仅支持字面量;useCurrent()和useCurrentOnUpdate()专用于时间戳字段且需配合非空约束;字符串默认值应依语义选''或null;回滚不清理默认值约束,需手动处理。

迁移里用 default() 不生效?先看数据库驱动类型
MySQL 和 PostgreSQL 对默认值的处理逻辑不同,Laravel 的 default() 方法在某些场景下只是“告诉迁移生成 SQL”,实际是否写入表结构,取决于底层驱动和字段类型。
- MySQL 5.7+:支持
TINYINT、VARCHAR等常见类型直接设默认值,但TEXT、JSON、NULL字段不支持原生默认值(会静默忽略default()) - PostgreSQL:对
NULL字段设default()是合法的,但若字段声明为nullable()又同时调用default(''),迁移可能报错或行为不一致 - SQLite:默认值只支持字面量(如
'hello'、123),不支持函数表达式(如now()),Laravel 会跳过校验直接写入,运行时才暴露问题
useCurrent() 和 useCurrentOnUpdate() 到底该谁用
这两个方法不是“设置 PHP 默认值”,而是让数据库自己生成时间戳 —— 所以它们只对 timestamp / datetime 字段有效,且必须配合 nullable(false) 或显式 default(null) 使用,否则 MySQL 8.0+ 会因严格模式拒绝建表。
-
useCurrent()→ 对应 SQL 的DEFAULT CURRENT_TIMESTAMP,仅插入时生效 -
useCurrentOnUpdate()→ 对应ON UPDATE CURRENT_TIMESTAMP,更新时自动刷新(注意:MySQL 中它会隐式让字段变成NOT NULL,即使你写了nullable()) - 想让 created_at 和 updated_at 都带默认值?两个都得写,但顺序无关;如果只写
useCurrentOnUpdate()而没写useCurrent(),插入时该字段会是NULL(除非你额外default(null))
字符串字段设默认值,default('') 还是 default(null)?
这取决于业务语义和查询习惯。空字符串 '' 和 NULL 在 WHERE 查询、索引、Eloquent 比较中表现完全不同。
- 用
default(''):适合“这个字段一定有值,只是可能为空字符串”,比如用户昵称允许为空但需参与索引或全文搜索 - 用
default(null):适合“该值尚未提供或不适用”,比如中间件记录的referer字段,未来源时就该是NULL,避免污染统计 - MySQL 中,
VARCHAR设default('')没问题;但如果你用的是TEXT,Laravel 迁移会生成成功,实际执行时 MySQL 报错Invalid default value for 'xxx'—— 此时只能换字段类型或放弃默认值
回滚迁移时默认值不会自动清除
这是最容易被忽略的一点:Laravel 的 php artisan migrate:rollback 只删表或删字段,不会还原字段的默认值约束。也就是说,你加了一个 default(1),回滚后再重跑迁移,新字段依然带着旧默认值 —— 因为 default() 是在 up() 里执行的 DDL,而 down() 通常只做 dropColumn() 或 dropIfExists(),不碰约束。
- 如果要确保每次迁移都干净重建默认值,得在
down()里手动用DB::statement()删除 DEFAULT 约束(MySQL:ALTER TABLE xxx ALTER COLUMN yyy DROP DEFAULT) - 更稳妥的做法是:把字段默认值逻辑收口到模型的
$attributes或访问器里,而不是全靠数据库层兜底 - 尤其在线上环境反复改表时,别依赖迁移自动管理默认值;先查
SHOW CREATE TABLE确认当前约束状态,再决定是否补 DDL


















