Laravel如何做数据库迁移字段默认表达式_LaravelDB::raw设置当前时间【指南】
Laravel数据库迁移中设置时间戳默认值应使用useCurrent()和useCurrentOnUpdate(),而非DB::raw()。前者兼容多数据库且生成合规SQL,后者在MySQL5.6.5以下或严格模式下因引号导致DEFAULT失效。
Lara vel 迁移中应使用 useCurrent() 和 useCurrentOnUpdate() 设置时间戳默认值,而非 DB::raw();前者适配多数据库并生成合规 SQL,后者在 MySQL 5.6.5+ 以下或严格模式下易因引号导致 DEFAULT 值失效。

先亮明结论:MySQL 5.6.5+ 或 PostgreSQL 才能用 DB::raw() 给字段设默认时间表达式;而在 Lara vel 迁移里,直接写 useCurrent() 或 useCurrentOnUpdate() 不仅更安全,可移植性也好得多。
MySQL 中用 DB::raw('CURRENT_TIMESTAMP') 设默认值会失败
不少开发者会习惯性地这么写:
Schema::table('posts', function (Blueprint $table) {
$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'))->change();
});
一段看似理所当然的代码,在 MySQL 5.6.5 以下或开启严格模式时,直接就会给你一个 SQLSTATE[HY000]: General error: 1067 Invalid default value for 'created_at' 的错误提示。核心问题在于:MySQL 的严格模式要求 TIMESTAMP / DATETIME 字段的默认表达式必须是常量(比如 CURRENT_TIMESTAMP),但 Lara vel 的 DB::raw() 在 default() 中并不会被识别为“字面量”,而是被当作字符串值插入。最终生成的 SQL 大致会是 DEFAULT 'CURRENT_TIMESTAMP' —— 多了引号,自然就失效了。
- MySQL 5.6.5+ 本身支持
CURRENT_TIMESTAMP作为默认值,但要求必须不带引号。 - Lara vel 8+ 提供的
useCurrent()方法,会自动生成不带引号的DEFAULT CURRENT_TIMESTAMP。 - 如果非要硬写
DB::raw(),也只能绕道DB::statement()手写原生 SQL,但这样一来,迁移的回滚和可逆性就全丢了。
useCurrent() 和 useCurrentOnUpdate() 才是正解
这两个方法就是为时间戳默认值量身定制的。它们能自动适配不同数据库驱动,并且生成合规的 SQL,省心得多:
Schema::table('posts', function (Blueprint $table) {
$table->timestamp('created_at')->useCurrent()->change();
$table->timestamp('updated_at')->useCurrentOnUpdate()->change();
});
有几个关键点需要留意:
useCurrent()对应CURRENT_TIMESTAMP,一般只用于created_at这类创建时间字段。useCurrentOnUpdate()会生成CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,非常适合updated_at这种更新时间字段。- 这两个方法仅对
timestamp()和datetime()字段有效,date()字段是没办法用的。 - 如果字段已经存在,记得配合
->change(),同时项目里需要启用doctrine/dbal扩展。
PostgreSQL 用户别用 DB::raw() 模拟默认时间
PostgreSQL 的情况又有点不同,它不支持 CURRENT_TIMESTAMP 作为列默认值的简写语法——必须用显式的函数调用。但 Lara vel 的 useCurrent() 在 PG 下会自动转为 now(),就解决了这个问题。而 useCurrentOnUpdate() 在 PostgreSQL 中无效(因为 PG 没有原生的 ON UPDATE 机制,需要另起炉灶用触发器)。
所以,针对 PostgreSQL 环境:
useCurrent()是安全可用的,它会生成DEFAULT now()。- 不建议手动写
default(DB::raw('now()'))—— 看似能用,但DB::raw()会绕过 Lara vel 的类型推断,后续执行change()时很可能失败。 - 如果需要自动更新字段时间,更可靠的做法是利用模型的
updating()事件或直接写数据库触发器,别指望着在迁移层一劳永逸。
真正容易被忽略的,往往是数据库版本和方言之间的差异。同一段迁移代码,在 MySQL 5.6、8.0、SQLite 和 PostgreSQL 下跑出来的结果可能天差地别。useCurrent() 是 Lara vel 精心封装的兼容层,而 DB::raw() 就相当于裸奔——除非你确信目标环境,并且愿意为每个数据库平台单独维护 SQL,否则还是乖乖用封装好的方法更明智。










































