商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Laravel如何做数据库迁移字段默认表达式_LaravelDB::raw设置当前时间【指南】

Laravel如何做数据库迁移字段默认表达式_LaravelDB::raw设置当前时间【指南】

  发布于2026-07-09 阅读(0)

扫一扫,手机访问

Lara vel 迁移中应使用 useCurrent() 和 useCurrentOnUpdate() 设置时间戳默认值,而非 DB::raw();前者适配多数据库并生成合规 SQL,后者在 MySQL 5.6.5+ 以下或严格模式下易因引号导致 DEFAULT 值失效。

Lara vel如何做数据库迁移字段默认表达式_Lara velDB::raw设置当前时间【指南】

先亮明结论: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,否则还是乖乖用封装好的方法更明智。

本文转载于:https://www.php.cn/faq/2409878.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注