composer中如何通过脚本自动执行数据库迁移_composer自定义命令实战【详解】

9次阅读

composer 的 scripts 可在 post-install-cmd 和 post-update-cmd 中执行迁移命令,支持 laravelsymfony、Phinx 等框架,通过环境变量控制行为,失败时中断流程保障 CI 安全。

composer中如何通过脚本自动执行数据库迁移_composer自定义命令实战【详解】

composer.json 里怎么写 post-install-cmd 和 post-update-cmd 脚本

Composer 的 scripts 是最轻量的自动化入口,适合在依赖安装/更新后自动跑迁移。它不依赖 Laravel 或 Symfony 的命令系统,纯靠 shell 命令或 php 脚本触发。

关键点:这些钩子默认在项目根目录执行,所以 php artisan migrate 能直接运行的前提是项目已装好 Laravel 并且 artisan 在当前路径下;否则会报 Command "migrate" is not defined

  • 只对 Laravel 项目有效?不是。只要脚本能调通,你可以写 php bin/console doctrine:migrations:migrate(Symfony)或 php vendor/bin/phinx migrate(Phinx)
  • 想区分开发/生产环境?用 app_ENV 环境变量控制,例如:"php artisan migrate --force --env=production",但注意 --force 在生产必须显式加,否则交互式确认会卡住
  • 迁移失败会导致 composer install 整体退出(exit code ≠ 0),CI 流程会中断——这反而是你想要的行为,避免部署半截数据库
{     "scripts": {         "post-install-cmd": [             "@php artisan migrate --no-interaction"         ],         "post-update-cmd": [             "@php artisan migrate --no-interaction"         ]     } }

自定义 Composer 命令:用 ScriptHandler 实现跨框架兼容

硬写 shell 命令容易耦合框架,换种方式:写一个 PHP 类,让 Composer 直接调它的静态方法。这样能复用应用的容器、配置、环境判断逻辑,也方便加日志或 try/catch

比如新建 scripts/databaseMigrator.php

&1');         echo $result;         if (strpos($result, 'Nothing to migrate') === false && strpos($result, 'Migrated:') === false) {             throw new RuntimeException("Migration failed:n{$result}");         }     } }

然后在 composer.json 中注册:

{     "autoload": {         "psr-4": {             "App\Scripts\": "scripts/"         }     },     "scripts": {         "migrate-db": [             "App\Scripts\DatabaseMigrator::run"         ]     } }

之后就能手动执行:composer migrate-db,也可被其他脚本调用(如 "post-update-cmd": ["@migrate-db"])。

为什么 migrate 经常卡在 “Waiting for lock” 或提示 “table doesn’t exist”

这不是 Composer 问题,而是迁移命令本身在并发或环境不一致时暴露的底层矛盾。常见于 CI/CD 或多实例部署场景。

  • Waiting for lock:Laravel 默认用文件锁(storage/framework/cache/data/...),CI 容器无共享存储 → 改用 redis 或 database 驱动锁,或在 config/cache.php 中设 'default' => 'Array'(仅限单次执行)
  • Base table or view not found:说明 migrations 表本身不存在,而 Laravel 迁移命令默认假设它已存在。首次部署需先运行 php artisan migrate:install,再跑 migrate
  • 本地开发没问题,CI 报错?检查 .env 是否被 git 忽略,CI 环境是否漏配 DB_DATABASE 或权限不足(如 mysql 用户没 CREATE 权限)

真正要小心的是“自动迁移”的边界

自动执行 migrate 很方便,但线上环境永远不该依赖它完成关键变更。比如加非空字段、删列、改索引类型——这些操作在大数据表上会锁表数分钟,而 Composer 钩子没有超时控制,会拖垮整个部署流程。

更稳妥的做法是:

  • 把高危迁移拆成独立命令,如 composer migrate-safe(只跑 DDL 安全操作)和 composer migrate-risky(需人工确认)
  • 在 CI 中禁用所有自动迁移,改由部署脚本分步执行:先 php artisan migrate:status 检查差异,再人工审核 SQL
  • 始终保留 php artisan migrate:rollback --step=1 能回退的能力,别依赖 “下次 deploy 覆盖”

自动化的价值在于减少重复劳动,不是替代人的判断。数据库结构变更永远是最难 rollback 的环节,脚本越顺滑,越要盯紧它的输出和副作用。

text=ZqhQzanResources