跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

Laravel 11 数据库迁移与Seeding高级技巧

必须检查migrate --pretend输出:它显示当前迁移的SQL但不反映外键、索引等隐式变更,如change()可能丢弃全文索引;应结合本地实测、显式依赖控制Seeder、CI中隔离数据库并设超时保护。 迁移执行前必须检查
migrate --pretend
的真实输出 直接运行
php artisan migrate
有可能在生产环境误删字段或修改主键类型,尤其当 migration 文件里用了
change()
或
dropColumn()
。用
--pretend
能看到 SQL 但不执行,但它只显示当前 migration 的语句,不包含外键约束、索引重建等隐式操作。比如你改一个字段长度:
$table->string('email', 128)->change();
,MySQL 实际会执行
ALTER TABLE ... MODIFY email VARCHAR(128)
,但若原字段有全文索引,
--pretend
不会提示索引被丢弃。 建议步骤: 先在本地 SQLite 或干净 MySQL 实例上跑一次
php artisan migrate --pretend
,再手动执行生成的 SQL 看是否报错 对含
change()
、
renameColumn()
、
dropForeign()
的迁移,务必在
up()
开头加注释说明影响范围 上线前用
php artisan migrate:status
核对目标环境已执行的迁移列表,避免跳过依赖项 Seeder 中外键顺序错误导致
Integrity constraint violation
运行
php artisan db:seed
报
SQLSTATE[23000]: Integrity constraint violation
,大概率是 Seeder 类调用顺序不对。Laravel 默认按文件名字母序执行
DatabaseSeeder::call()
里的类,但数据库外键要求「父表数据先存在」。比如
RoleSeeder
和
UserSeeder
,如果
UserSeeder
先跑,而它插入的
role_id
指向还没创建的 role,就会失败。 解决办法不是靠文件名排序,而是显式控制依赖: 在
DatabaseSeeder.php
中按需调用:
$this->call([RoleSeeder::class, PermissionSeeder::class, UserSeeder::class]);
避免在单个 Seeder 里混合插入多模型数据(例如一边插 category,一边插 product),拆成独立类并明确 call 顺序 开发阶段可临时禁用外键检查:
DB::statement('SET FOREIGN_KEY_CHECKS=0');
,但仅限本地,切勿提交到版本库
migrate:fresh --seed
在 CI/CD 中要避开
DB_DATABASE
环境变量陷阱
php artisan migrate:fresh --seed
会删库重来,但它读取的是当前环境的
DB_DATABASE
。CI 流水线里如果没隔离数据库名,可能误清掉共享测试库。更隐蔽的问题是:Laravel 11 默认启用
DB_FOREIGN_KEYS=true
,而某些托管 MySQL 服务(如 AWS RDS)默认关闭外键支持,此时
migrate:fresh
会卡在
dropAllTables()
阶段,报错
Cannot delete or update a parent row
却不提示原因。 Laravel 13.2.0 PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。 下载 安全做法: CI 脚本中显式指定测试库:
DB_DATABASE=test_app_$$ php artisan migrate:fresh --seed
(
$$
是 shell 进程 PID,保证库名唯一) 在
phpunit.xml
的
env
节点里覆盖
DB_FOREIGN_KEYS=1
,而非依赖 .env 对
migrate:fresh
加超时保护:
timeout 60s php artisan migrate:fresh --seed || exit 1
Seeder 批量插入性能断崖出现在 500 条以上 用
DB::table()->insert()
插 1000 条用户,耗时可能从 0.2s 暴涨到 3s+,尤其在启用了
created_at
/
updated_at
自动填充、且表有多个索引时。这不是 Laravel Bug,而是 MySQL 批量 INSERT 的索引维护成本随行数非线性增长。 实测有效的优化点: 单次
insert()
最多塞 200~300 行,超过就分批;用
collect($data)->chunk(250)
切分 Seeder 开头关时间戳自动填充:
Model::withoutTimestamps(fn () => $this->call(UserSeeder::class));
若只是初始化基础数据(如国家列表),直接用
DB::unprepared(file_get_contents('sql/countries.sql'))
导入原始 SQL,比 PHP 循环快 5 倍以上 真正容易被忽略的是:Seeder 里用 Eloquent 模型 save() 插一条数据,会触发全部 boot()、mutator、observer,而
DB::table()->insert()
完全绕过这些。别为了“看起来优雅”在 Seeder 里滥用模型实例。

相关文章