Laravel迁移是数据库版本控制机制,需用php artisan make:migration生成带时间戳的脚本,通过Schema::create()建表、Schema::table()改表,严禁修改已提交迁移,生产环境须--force执行并规避锁表风险。

直接说结论:Laravel 的迁移不是“一键同步数据库结构”,而是通过版本化脚本控制表结构演进,必须配合 php artisan migrate 和团队协作规范才能可靠落地。
怎么创建一个带字段的迁移文件
别手写文件名,用 Artisan 命令生成,它会自动加上时间戳前缀,保证执行顺序:
php artisan make:migration create_users_table
打开生成的文件(路径类似 database/migrations/2024_05_20_103022_create_users_table.php),在 up() 方法里用 Schema 构建表:
public function up(MigrationBuilder $table)
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamps();
});
}
-
id()默认是自增主键,等价于$table->bigIncrements('id') -
timestamps()会加created_at和updated_at,类型是datetime,不是timestamp(MySQL 中有细微差异) - 如果字段要支持 NULL,显式写
$table->string('phone')->nullable(),不写就是 NOT NULL
运行迁移时常见的报错和应对
最常遇到的是 SQLSTATE[HY000]: General error: 1005 Can't create table 或外键失败,本质是 MySQL 引擎或字符集不匹配:
- 确认
config/database.php中 MySQL 连接配置启用了'engine' => null(Laravel 9+ 默认使用 InnoDB) - 检查迁移中是否对未存在的表加外键,比如先跑
add_foreign_key_to_posts_table,但users表还没建 —— 迁移执行顺序严格按文件名时间戳,别乱改名字 - 如果提示
Base table or view not found,说明该表已被手动删过,但migrations表里还记着已执行记录,此时不要直接删记录,先用php artisan migrate:rollback --step=1回退,再重试
修改已有表结构该用什么命令
永远不要直接改老迁移文件里的 up() —— 它可能已在其他环境执行过。正确做法是新建迁移:
php artisan make:migration add_avatar_to_users_table
然后在新文件中写变更逻辑:
public function up(MigrationBuilder $table)
{
Schema::table('users', function (Blueprint $table) {
$table->string('avatar')->nullable()->after('email');
});
}
-
Schema::table()是修改已有表,Schema::create()是建新表,别混用 -
after('email')控制字段位置,仅 MySQL 支持;SQLite 和 PostgreSQL 忽略该参数 - 如果要删字段,得先在
config/database.php中启用'strict' => false(MySQL)并确保开启了allow_drop_column(Laravel 10+ 默认允许),否则会报错
生产环境执行迁移要注意什么
线上不能只跑 php artisan migrate 就完事:
- 务必加
--force参数,否则交互式确认会卡住(尤其在部署脚本里) - 大表加索引或改字段类型(如 TEXT → JSON)可能锁表几分钟,得搭配
DB::statement()手动写带ALGORITHM=INPLACE的语句,或安排在低峰期 - 如果迁移里包含数据填充(比如预设角色),别写在
up()里 —— 应该用 Seeder,并通过php artisan db:seed --class=UserRolesSeeder单独触发 - 回滚(
migrate:rollback)只退最近一批(batch),不是单个迁移;要看清migrations表里的batch字段,避免误操作
迁移真正的难点不在语法,而在于多人并行开发时的冲突协调、线上灰度验证、以及回滚预案是否真能跑通 —— 很多团队出问题,都是因为把迁移当“建表工具”用,忘了它是数据库的版本控制机制。









