Laravel中支持哪些迁移字段类型?

2026-05-07 07:271阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

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

Laravel中支持哪些迁移字段类型?

Laravel 迁移中,避免使用万能字段,如 string、boolean、json、dateTime 等,这些类型覆盖 90% 场景。错误类型会导致查询失效、Eloquent 转换异常或跨库迁移失败。

boolean 字段不是存 0/1 的整数

很多人用 tinyInteger('is_active') 模拟开关,但这是错误的起点。Laravel 的 boolean('is_active') 在 MySQL 中生成 TINYINT(1),在 PostgreSQL 中生成 BOOLEAN,Eloquent 读取时自动转为 PHP true/false;而手动用 tinyInteger 存 0/1,Eloquent 不会做语义转换,$user->is_active === 0(int)而非 false(bool),后续 if ($user->is_active) 逻辑可能意外通过。

必须注意:

  • boolean 字段默认不允许 null,如需三态(启用/禁用/未设置),得显式加 ->nullable()
  • MySQL 5.7.2+ 支持原生 BOOLEAN,旧版会退化为 TINYINT,但 Laravel 层行为一致,无需额外适配
  • 不要用 enum 存开关状态——它把业务逻辑硬编码进数据库,改一个值要重跑迁移

JSON 字段不能靠 $casts 就万事大吉

json('settings') 是存储用户偏好、表单配置等非结构化数据的首选,但光在模型里写 'settings' => 'array' 远不够。Eloquent 确实会自动序列化/反序列化,但局部更新(比如只改 settings.theme)不会触发完整重写,必须用数据库原生函数。

常见踩坑点:

  • $user->settings['theme'] = 'dark'; $user->save(); 看似正常,实际是全量覆盖整个 JSON 字段,其他键值可能被意外清空(尤其并发写入时)
  • MySQL 中局部更新得用 DB::raw("JSON_SET(settings, '$.theme', 'dark')"),PostgreSQL 则用 jsonb_set(),语法不通用
  • where('settings->theme', 'dark') 查询在 SQLite 上不生效——它没 JSON 提取函数,会静默返回空结果

日期时间字段要小心精度和时区

dateTime('published_at')dateTimeTz('sent_at') 看似只差个 Tz,但底层差异极大:dateTime 存的是无时区时间戳(如 2026-04-24 15:30:00),数据库按服务器本地时区解释;dateTimeTz 则强制带时区信息(如 2026-04-24 15:30:00+08:00),PostgreSQL 原生支持,MySQL 8.0+ 才支持,SQLite 完全不支持。

实际影响:

  • 跨时区部署时,用 dateTime + 应用层统一 UTC 存储最稳妥;强行用 dateTimeTz 可能导致 MySQL 报错或降级为普通 datetime
  • 需要毫秒精度(比如日志追踪)?得显式指定 ->useMicroseconds(),否则默认秒级,2026-04-24 15:30:00.123 会被截断成 2026-04-24 15:30:00
  • timestamp 类型在 Laravel 迁移中不推荐直接使用——它受 MySQL explicit_defaults_for_timestamp 配置影响,行为不稳定

外键字段必须匹配被引用列的类型和符号

定义外键时,foreignId('user_id') 看起来方便,但它默认对应 unsignedBigInteger,如果被引用的 users.idincrements()(即 unsignedInteger),就会类型不匹配,MySQL 报错 Cannot add or update a child row: a foreign key constraint fails

安全做法:

  • 主键用 id()(等价于 bigIncrements)→ 外键统一用 foreignId
  • 主键用 increments → 外键必须用 unsignedInteger('user_id'),再手动 ->foreign('user_id')->references('id')->on('users')
  • 千万别混用 integerbigInteger 做关联,哪怕数值看起来能装下,数据库层面类型不一致就拒绝建约束

字段类型不是填空题,是设计决策。一个 json 字段写着写着变成嵌套三层对象,一个 string 字段从用户名膨胀到富文本 HTML,这些都不是类型本身的问题,而是当初没想清楚「这个字段未来会不会被 WHERE 条件查」「会不会被 ORDER BY 排序」「要不要被前端直接渲染」——类型选得对,后面少一半调试时间。

标签:Laravel

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

Laravel中支持哪些迁移字段类型?

Laravel 迁移中,避免使用万能字段,如 string、boolean、json、dateTime 等,这些类型覆盖 90% 场景。错误类型会导致查询失效、Eloquent 转换异常或跨库迁移失败。

boolean 字段不是存 0/1 的整数

很多人用 tinyInteger('is_active') 模拟开关,但这是错误的起点。Laravel 的 boolean('is_active') 在 MySQL 中生成 TINYINT(1),在 PostgreSQL 中生成 BOOLEAN,Eloquent 读取时自动转为 PHP true/false;而手动用 tinyInteger 存 0/1,Eloquent 不会做语义转换,$user->is_active === 0(int)而非 false(bool),后续 if ($user->is_active) 逻辑可能意外通过。

必须注意:

  • boolean 字段默认不允许 null,如需三态(启用/禁用/未设置),得显式加 ->nullable()
  • MySQL 5.7.2+ 支持原生 BOOLEAN,旧版会退化为 TINYINT,但 Laravel 层行为一致,无需额外适配
  • 不要用 enum 存开关状态——它把业务逻辑硬编码进数据库,改一个值要重跑迁移

JSON 字段不能靠 $casts 就万事大吉

json('settings') 是存储用户偏好、表单配置等非结构化数据的首选,但光在模型里写 'settings' => 'array' 远不够。Eloquent 确实会自动序列化/反序列化,但局部更新(比如只改 settings.theme)不会触发完整重写,必须用数据库原生函数。

常见踩坑点:

  • $user->settings['theme'] = 'dark'; $user->save(); 看似正常,实际是全量覆盖整个 JSON 字段,其他键值可能被意外清空(尤其并发写入时)
  • MySQL 中局部更新得用 DB::raw("JSON_SET(settings, '$.theme', 'dark')"),PostgreSQL 则用 jsonb_set(),语法不通用
  • where('settings->theme', 'dark') 查询在 SQLite 上不生效——它没 JSON 提取函数,会静默返回空结果

日期时间字段要小心精度和时区

dateTime('published_at')dateTimeTz('sent_at') 看似只差个 Tz,但底层差异极大:dateTime 存的是无时区时间戳(如 2026-04-24 15:30:00),数据库按服务器本地时区解释;dateTimeTz 则强制带时区信息(如 2026-04-24 15:30:00+08:00),PostgreSQL 原生支持,MySQL 8.0+ 才支持,SQLite 完全不支持。

实际影响:

  • 跨时区部署时,用 dateTime + 应用层统一 UTC 存储最稳妥;强行用 dateTimeTz 可能导致 MySQL 报错或降级为普通 datetime
  • 需要毫秒精度(比如日志追踪)?得显式指定 ->useMicroseconds(),否则默认秒级,2026-04-24 15:30:00.123 会被截断成 2026-04-24 15:30:00
  • timestamp 类型在 Laravel 迁移中不推荐直接使用——它受 MySQL explicit_defaults_for_timestamp 配置影响,行为不稳定

外键字段必须匹配被引用列的类型和符号

定义外键时,foreignId('user_id') 看起来方便,但它默认对应 unsignedBigInteger,如果被引用的 users.idincrements()(即 unsignedInteger),就会类型不匹配,MySQL 报错 Cannot add or update a child row: a foreign key constraint fails

安全做法:

  • 主键用 id()(等价于 bigIncrements)→ 外键统一用 foreignId
  • 主键用 increments → 外键必须用 unsignedInteger('user_id'),再手动 ->foreign('user_id')->references('id')->on('users')
  • 千万别混用 integerbigInteger 做关联,哪怕数值看起来能装下,数据库层面类型不一致就拒绝建约束

字段类型不是填空题,是设计决策。一个 json 字段写着写着变成嵌套三层对象,一个 string 字段从用户名膨胀到富文本 HTML,这些都不是类型本身的问题,而是当初没想清楚「这个字段未来会不会被 WHERE 条件查」「会不会被 ORDER BY 排序」「要不要被前端直接渲染」——类型选得对,后面少一半调试时间。

标签:Laravel