yii migrate 是一个数据库迁移工具,它允许你通过版本化的 PHP 脚本来管理数据库结构的变更,这比手动编写和执行 SQL 文件要安全、可追溯得多,尤其是在团队协作和项目迭代中。

什么是数据库迁移?
数据库迁移可以理解为对数据库结构(如表、字段、索引等)的“版本控制”。
- 传统方式:你可能手动创建
create_user_table.sql,add_email_to_user.sql等文件,当多人协作时,很容易忘记执行某个脚本,或者执行顺序错误,导致数据库结构不一致。 - 迁移方式:每次需要修改数据库结构时,你都会创建一个新的“迁移”文件(一个 PHP 类),这个文件包含了执行变更(
up()方法)和回滚变更(down()方法)的代码。yii migrate命令会跟踪已经应用过的迁移,并确保只执行未应用的迁移。
常用命令详解
在终端中,你需要进入你的 Yii2 项目的根目录(即 yii 控制台脚本所在的目录),然后执行以下命令。
1 创建新的迁移文件
这是所有工作的第一步,当你需要创建、修改或删除表时,首先用这个命令生成一个迁移文件骨架。
# 基础语法 yii migrate/create <name_of_your_migration> # 示例:创建一个用于创建 'news' 表的迁移 yii migrate/create create_news_table # 示例:创建一个用于在 'user' 表中添加 'bio' 字段的迁移 yii migrate/add_column_to_user_bio # 示例:创建一个用于删除 'post' 表的迁移 yii migrate/create drop_post_table
执行后会发生什么?

Yii 会在 @app/migrations 目录下创建一个新的 PHP 文件,文件名类似 m200101_120000_create_news_table.php。
示例:**
<?php
use yii\db\Migration;
/**
* Handles the creation of table `{{%news}}`.
*/
class m200101_120000_create_news_table extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->createTable('{{%news}}', [
'id' => $this->primaryKey(),
'title' => $this->string(255)->notNull(),
'content' => $this->text(),
'status' => $this->smallInteger()->notNull()->defaultValue(0),
'created_at' => $this->integer(),
'updated_at' => $this->integer(),
]);
}
/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropTable('{{%news}}');
}
}
safeUp(): 定义了“向上”迁移的逻辑,即应用这个迁移时需要执行的代码(如创建表、添加字段)。safeDown(): 定义了“向下”迁移的逻辑,即回滚这个迁移时需要执行的代码(如删除表、删除字段),这是迁移安全性的关键,确保你可以撤销变更。{{%news}}: 这是 Yii2 的表名语法。 会被替换为你配置在db组件中的表前缀(tablePrefix),这是一个好习惯。
2 应用迁移
这是最常用的命令,它会执行所有尚未应用的迁移的 safeUp() 方法。
# 应用所有待执行的迁移 yii migrate
交互式执行: 执行这个命令后,Yii 会列出将要应用的迁移,并询问你是否继续:
Yii Migration Tool (based on Yii v2.0.45)
Total new migrations to be applied:
m200101_120000_create_news_table
Apply the above migration? (yes/no) [no]: yes
输入 yes 并回车,迁移开始执行。

非交互式执行: 在脚本或自动化流程中,你可能希望自动执行,而不需要手动确认。
# 自动应用所有待执行的迁移 yii migrate/up
应用指定数量的迁移:
# 只应用下一个迁移 yii migrate/up -n # 应用接下来的 3 个迁移 yii migrate/up -n 3
3 回滚迁移
回滚会执行最近应用的迁移的 safeDown() 方法,以撤销数据库变更。
# 回滚上一个迁移 yii migrate/down
回滚指定数量的迁移:
# 回滚最近的 3 个迁移 yii migrate/down -n 3
⚠️ 重要提示: 确保你的 safeDown() 方法能够完美地撤销 safeUp() 所做的所有操作。safeUp() 创建了表,safeDown() 必须删除它。safeUp() 添加了外键,safeDown() 必须删除它。
4 查看迁移历史
查看哪些迁移已经被应用,哪些还未应用。
# 查看迁移历史 yii migrate/history # 示例输出: # m200101_120000_create_news_table # m200102_050000_add_column_to_user_bio
# 查看待执行的迁移 yii migrate/new # 示例输出: # m200103_100000_create_post_table
5 重新应用迁移
这个命令会先回滚一个已应用的迁移,然后立即重新应用它,这对于调试迁移脚本非常有用。
# 重新应用上一个迁移 yii migrate/redo
6 标记迁移为已应用
在某些特殊情况下(你手动在数据库中执行了 SQL,但想告诉 Yii 这个迁移已经完成),你可以使用这个命令来伪造一个迁移记录。
# 标记指定的迁移为已应用,但不执行其代码 yii migrate/mark m200101_120000_create_news_table
7 刷新整个迁移历史
这是一个危险的操作!它会删除 migration 表中的所有记录,并重置自增 ID,这通常用于开发环境,当你想彻底清空迁移历史并重新开始时。
# 刷新迁移历史 yii migrate/fresh
警告: 执行此命令后,所有迁移都将被视为“未应用”,你需要从头开始重新运行 yii migrate/up,请确保在执行前备份你的数据库!
最佳实践
- 原子性:一个迁移文件只做一件事。
create_user_table和add_email_to_user_table应该是两个独立的迁移。 - 可回滚:始终认真编写
safeDown()方法,未来的你或你的同事会感谢你。 - 团队协作:将
migrations目录提交到版本控制系统(如 Git),这样每个团队成员都能获取到最新的数据库结构变更脚本。 - 环境隔离:在开发、测试和生产环境中使用相同的迁移流程,不要在生产数据库上手动执行 SQL,始终通过
yii migrate来操作。 - 数据迁移:
yii migrate主要用于结构变更,如果你需要在结构变更的同时迁移数据(重命名一个字段并更新其值),你可以在safeUp()中使用$this->update()或$this->insert()等方法来完成。
常见问题
Q: 迁移失败怎么办?
A: 迁移是事务性的。safeUp() 执行过程中发生错误,整个事务会回滚,数据库将保持不变,并且该迁移不会被标记为已应用,你需要先修复代码中的错误,然后重新运行 yii migrate/up。
Q: 我可以手动修改已应用的迁移文件吗? A: 绝对不要! 这会破坏迁移的版本控制逻辑,导致数据库状态与迁移历史不一致,引发严重问题,如果需要修改已应用的逻辑,应该创建一个新的迁移来完成后续的变更。
Q: 如何在迁移中使用数据表前缀?
A: 如前所述,使用 {{%table_name}} 语法即可,Yii2 会自动将 替换为你配置的表前缀。
