Laravel数据库迁移中,如何使用DB::raw设置字段默认当前时间值?

2026-05-03 00:193阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计758个文字,预计阅读时间需要4分钟。

Laravel数据库迁移中,如何使用DB::raw设置字段默认当前时间值?

MySQL 5.6.5 或 PostgreSQL 才能使用 DB::raw() 给字段设置默认时间表达式,Laravel 迁移里直接写 + 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),但 Laravel 的 DB::raw()default() 中不会被识别为“字面量”,而是当成字符串值插入,最终生成类似 DEFAULT 'CURRENT_TIMESTAMP' 的 SQL —— 带引号就失效了。

  • MySQL 5.6.5+ 支持 CURRENT_TIMESTAMP 作为默认值,但必须不带引号
  • Laravel 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 作为列默认值的简写语法(它要求显式函数调用)。但 Laravel 的 useCurrent() 会自动转成 now(),而 useCurrentOnUpdate() 在 PG 中无效(PG 无原生 ON UPDATE 支持,得靠触发器)。所以:

  • PG 下 useCurrent() 安全可用,生成 DEFAULT now()
  • 不要手动写 default(DB::raw('now()')) —— 看似可行,但 DB::raw() 会绕过 Laravel 的类型推断,导致后续 change() 失败
  • 需要自动更新时间?用模型的 updating() 事件或数据库触发器,别强求迁移层解决

真正容易被忽略的是数据库版本和方言差异:同一段迁移代码,在 MySQL 5.6 和 8.0、SQLite 和 PG 下行为可能完全不同。useCurrent() 是 Laravel 封装的兼容层,而 DB::raw() 是裸奔 —— 除非你明确知道目标环境并愿意为每个平台单独维护 SQL,否则别碰。

标签:Laravel

本文共计758个文字,预计阅读时间需要4分钟。

Laravel数据库迁移中,如何使用DB::raw设置字段默认当前时间值?

MySQL 5.6.5 或 PostgreSQL 才能使用 DB::raw() 给字段设置默认时间表达式,Laravel 迁移里直接写 + 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),但 Laravel 的 DB::raw()default() 中不会被识别为“字面量”,而是当成字符串值插入,最终生成类似 DEFAULT 'CURRENT_TIMESTAMP' 的 SQL —— 带引号就失效了。

  • MySQL 5.6.5+ 支持 CURRENT_TIMESTAMP 作为默认值,但必须不带引号
  • Laravel 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 作为列默认值的简写语法(它要求显式函数调用)。但 Laravel 的 useCurrent() 会自动转成 now(),而 useCurrentOnUpdate() 在 PG 中无效(PG 无原生 ON UPDATE 支持,得靠触发器)。所以:

  • PG 下 useCurrent() 安全可用,生成 DEFAULT now()
  • 不要手动写 default(DB::raw('now()')) —— 看似可行,但 DB::raw() 会绕过 Laravel 的类型推断,导致后续 change() 失败
  • 需要自动更新时间?用模型的 updating() 事件或数据库触发器,别强求迁移层解决

真正容易被忽略的是数据库版本和方言差异:同一段迁移代码,在 MySQL 5.6 和 8.0、SQLite 和 PG 下行为可能完全不同。useCurrent() 是 Laravel 封装的兼容层,而 DB::raw() 是裸奔 —— 除非你明确知道目标环境并愿意为每个平台单独维护 SQL,否则别碰。

标签:Laravel