如何通过Laravel生成并执行数据库迁移文件?

2026-04-28 23:024阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

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

如何通过Laravel生成并执行数据库迁移文件?

文件名修改不会影响执行逻辑,但Laravel会检查文件名是否包含特定前缀,如create_或add_,来自动填充模板内容。例如,php artisan make:migration create_users_table会生成带有Schema::create(')的空表结构;而php artisan make:migration add_phone_to_users_table则默认使用Schema::table('),适用于添加字段。

常见错误是手误写成 create_user_table(少个 s),结果生成的迁移里表名是 user,上线后报 Table 'user' doesn't exist —— 因为 Laravel 默认复数表名,且多数约定是 users

  • 命名建议统一用复数 + _table 后缀,如 create_posts_table
  • 如果想跳过自动模板、完全自定义,加 --plain 参数:php artisan make:migration rename_user_email --plain
  • 别依赖文件名推断逻辑,打开生成的文件第一眼确认 up() 里调用的是 create() 还是 table()

执行迁移前,先看 php artisan migrate:statusphp artisan migrate --pretend

直接 php artisan migrate 很快,但出错就难回退。尤其在生产环境或多人协作时,你不知道别人有没有提交新迁移却没跑,也不知道当前本地数据库状态是否和代码一致。

php artisan migrate:status 会列出所有迁移文件及其 Ran? 状态,一眼看出哪些漏了、哪些失败了;php artisan migrate --pretend 则把实际要执行的 SQL 打印出来,不真跑 —— 这能帮你提前发现字段类型冲突、索引重名、外键约束缺失等硬伤。

  • --pretend 输出的 SQL 是基于当前数据库连接配置的,所以务必先确认 .envDB_DATABASE 指向的是你打算操作的库
  • 如果看到 ALTER TABLE users ADD COLUMN phone VARCHAR(20),但 users 表已经有百万行,就得警惕:这个操作在 MySQL 5.6+ 虽支持 online DDL,但依然可能锁表几秒,得避开高峰
  • 状态命令不显示失败详情,若某次迁移卡住,先查 failed_jobs 表或日志里的具体异常,再决定是 rollback 还是手动修复

down() 方法不是必须写全,但删字段/删表必须显式处理

Laravel 不强制要求每个迁移都实现可逆逻辑,down() 留空也能跑 migrate。但如果你写了 down() 却没覆盖所有 up() 的副作用,比如只删了字段却忘了删对应索引,下次回滚再迁移就会报 Index name already exists

更麻烦的是,Laravel 8+ 默认禁用 dropColumn() 在 SQLite 和某些旧版 MySQL 上的使用 —— 它底层靠重建表实现,容易丢数据或触发严格模式报错。

  • 新增字段、索引、外键,down() 一般只需反向操作:用 dropColumn()dropIndex()dropForeign()
  • 删除字段?优先考虑保留字段、加注释标记废弃,而不是真删 —— 回滚风险高,ORM 层也可能残留引用
  • 真要删,MySQL 8.0+ 可用 dropColumn(),但得确保 DB_STRICT_MODE=true 关闭,否则可能因默认值校验失败

多环境部署时,migrate 命令必须加 --force 才能在生产环境运行

Laravel 默认在非本地环境禁止执行迁移,防止误操作炸掉线上库。所以你在服务器上跑 php artisan migrate,大概率看到 Nothing to migrate. 或直接报错,不是没新迁移,而是被安全机制拦住了。

这个开关藏在 APP_ENVAPP_DEBUG 之后,核心逻辑是:只要 APP_ENV 不是 local,就必须显式加 --force。而且它不接受 --force=true 这种写法,只能是 --force

  • CI/CD 流水线里记得加参数:php artisan migrate --force --no-interaction,后者避免交互式确认卡住
  • 别在 .env 里临时改 APP_ENV=local 来绕过,这会让日志、缓存、异常页面全变成开发态,暴露敏感信息
  • 如果用了多数据库连接(比如 tenants),还得指定 --database=tenant1,否则默认只跑主库

迁移不是“写完就能跑”,它是数据库 schema 的版本控制动作,每一步背后都有隐式依赖和环境假设。最常出问题的,往往不是语法错误,而是没看清当前连接的是哪个库、没确认 up()down() 是否真正对称、或者忘了生产环境那道 --force 的门禁。

标签:Laravel

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

如何通过Laravel生成并执行数据库迁移文件?

文件名修改不会影响执行逻辑,但Laravel会检查文件名是否包含特定前缀,如create_或add_,来自动填充模板内容。例如,php artisan make:migration create_users_table会生成带有Schema::create(')的空表结构;而php artisan make:migration add_phone_to_users_table则默认使用Schema::table('),适用于添加字段。

常见错误是手误写成 create_user_table(少个 s),结果生成的迁移里表名是 user,上线后报 Table 'user' doesn't exist —— 因为 Laravel 默认复数表名,且多数约定是 users

  • 命名建议统一用复数 + _table 后缀,如 create_posts_table
  • 如果想跳过自动模板、完全自定义,加 --plain 参数:php artisan make:migration rename_user_email --plain
  • 别依赖文件名推断逻辑,打开生成的文件第一眼确认 up() 里调用的是 create() 还是 table()

执行迁移前,先看 php artisan migrate:statusphp artisan migrate --pretend

直接 php artisan migrate 很快,但出错就难回退。尤其在生产环境或多人协作时,你不知道别人有没有提交新迁移却没跑,也不知道当前本地数据库状态是否和代码一致。

php artisan migrate:status 会列出所有迁移文件及其 Ran? 状态,一眼看出哪些漏了、哪些失败了;php artisan migrate --pretend 则把实际要执行的 SQL 打印出来,不真跑 —— 这能帮你提前发现字段类型冲突、索引重名、外键约束缺失等硬伤。

  • --pretend 输出的 SQL 是基于当前数据库连接配置的,所以务必先确认 .envDB_DATABASE 指向的是你打算操作的库
  • 如果看到 ALTER TABLE users ADD COLUMN phone VARCHAR(20),但 users 表已经有百万行,就得警惕:这个操作在 MySQL 5.6+ 虽支持 online DDL,但依然可能锁表几秒,得避开高峰
  • 状态命令不显示失败详情,若某次迁移卡住,先查 failed_jobs 表或日志里的具体异常,再决定是 rollback 还是手动修复

down() 方法不是必须写全,但删字段/删表必须显式处理

Laravel 不强制要求每个迁移都实现可逆逻辑,down() 留空也能跑 migrate。但如果你写了 down() 却没覆盖所有 up() 的副作用,比如只删了字段却忘了删对应索引,下次回滚再迁移就会报 Index name already exists

更麻烦的是,Laravel 8+ 默认禁用 dropColumn() 在 SQLite 和某些旧版 MySQL 上的使用 —— 它底层靠重建表实现,容易丢数据或触发严格模式报错。

  • 新增字段、索引、外键,down() 一般只需反向操作:用 dropColumn()dropIndex()dropForeign()
  • 删除字段?优先考虑保留字段、加注释标记废弃,而不是真删 —— 回滚风险高,ORM 层也可能残留引用
  • 真要删,MySQL 8.0+ 可用 dropColumn(),但得确保 DB_STRICT_MODE=true 关闭,否则可能因默认值校验失败

多环境部署时,migrate 命令必须加 --force 才能在生产环境运行

Laravel 默认在非本地环境禁止执行迁移,防止误操作炸掉线上库。所以你在服务器上跑 php artisan migrate,大概率看到 Nothing to migrate. 或直接报错,不是没新迁移,而是被安全机制拦住了。

这个开关藏在 APP_ENVAPP_DEBUG 之后,核心逻辑是:只要 APP_ENV 不是 local,就必须显式加 --force。而且它不接受 --force=true 这种写法,只能是 --force

  • CI/CD 流水线里记得加参数:php artisan migrate --force --no-interaction,后者避免交互式确认卡住
  • 别在 .env 里临时改 APP_ENV=local 来绕过,这会让日志、缓存、异常页面全变成开发态,暴露敏感信息
  • 如果用了多数据库连接(比如 tenants),还得指定 --database=tenant1,否则默认只跑主库

迁移不是“写完就能跑”,它是数据库 schema 的版本控制动作,每一步背后都有隐式依赖和环境假设。最常出问题的,往往不是语法错误,而是没看清当前连接的是哪个库、没确认 up()down() 是否真正对称、或者忘了生产环境那道 --force 的门禁。

标签:Laravel