9 个关注者

数据库迁移

在开发和维护一个数据库驱动应用程序的过程中,所使用的数据库的结构会像源代码一样发生变化。例如,在开发应用程序期间,可能会发现需要一个新的表;应用程序部署到生产环境后,可能会发现应该创建一个索引来提高查询性能,等等。由于数据库结构更改通常需要一些源代码更改,Yii 支持所谓的数据库迁移功能,允许您将数据库更改跟踪为数据库迁移,这些迁移与源代码一起进行版本控制。

以下步骤展示了开发过程中团队如何使用数据库迁移。

  1. Tim 创建一个新的迁移(例如,创建一个新表,更改一个列定义,等等)。
  2. Tim 将新的迁移提交到源代码控制系统(例如,Git、Mercurial)。
  3. Doug 从源代码控制系统更新他的存储库,并接收新的迁移。
  4. Doug 将迁移应用到他的本地开发数据库,从而同步他的数据库以反映 Tim 所做的更改。

以下步骤展示了如何将新版本和数据库迁移部署到生产环境。

  1. Scott 为包含一些新的数据库迁移的项目存储库创建一个发布标签。
  2. Scott 将生产服务器上的源代码更新到发布标签。
  3. Scott 将任何累积的数据库迁移应用到生产数据库。

Yii 提供了一套迁移命令行工具,允许您

  • 创建新的迁移;
  • 应用迁移;
  • 还原迁移;
  • 重新应用迁移;
  • 显示迁移历史和状态。

所有这些工具都可以通过命令 yii migrate 访问。在本节中,我们将详细描述如何使用这些工具完成各种任务。您也可以通过帮助命令 yii help migrate 获取每个工具的使用方法。

提示:迁移不仅可以影响数据库架构,还可以调整现有数据以适应新架构,创建 RBAC 层级或清理缓存。

注意: 当使用迁移操作数据时,您可能会发现使用您的 Active Record 类会很有用,因为其中已经实现了一些逻辑。但是请记住,与迁移中编写的代码不同,迁移代码的性质是永远保持不变,而应用程序逻辑可能会发生变化。因此,在迁移代码中使用 Active Record 时,Active Record 层逻辑的更改可能会意外破坏现有的迁移。出于这个原因,迁移代码应保持独立于其他应用程序逻辑,例如 Active Record 类。

创建迁移

要创建新的迁移,请运行以下命令

yii migrate/create <name>

必需的 name 参数提供了关于新迁移的简要描述。例如,如果迁移是关于创建一个名为 news 的新表,您可以使用名称 create_news_table 并运行以下命令

yii migrate/create create_news_table

注意: 因为 name 参数将用作生成的迁移类名的一部分,所以它应该只包含字母、数字和/或下划线字符。

以上命令将在 @app/migrations 目录中创建一个名为 m150101_185401_create_news_table.php 的新 PHP 类文件。该文件包含以下代码,该代码主要声明了一个带有基本代码的迁移类 m150101_185401_create_news_table

<?php

use yii\db\Migration;

class m150101_185401_create_news_table extends Migration
{
    public function up()
    {

    }

    public function down()
    {
        echo "m101129_185401_create_news_table cannot be reverted.\n";

        return false;
    }

    /*
    // Use safeUp/safeDown to run migration code within a transaction
    public function safeUp()
    {
    }

    public function safeDown()
    {
    }
    */
}

每个数据库迁移都定义为一个从 yii\db\Migration 扩展的 PHP 类。迁移类名自动生成,格式为 m<YYMMDD_HHMMSS>_<Name>,其中

  • <YYMMDD_HHMMSS> 指的是执行迁移创建命令时的 UTC 日期时间。
  • <Name> 与您提供给命令的 name 参数的值相同。

在迁移类中,您需要在 up() 方法中编写代码,以对数据库结构进行更改。您可能还想在 down() 方法中编写代码以撤消 up() 所做的更改。当您使用此迁移升级数据库时,将调用 up() 方法,而当您降级数据库时,将调用 down() 方法。以下代码展示了如何实现迁移类以创建一个 news

<?php

use yii\db\Schema;
use yii\db\Migration;

class m150101_185401_create_news_table extends Migration
{
    public function up()
    {
        $this->createTable('news', [
            'id' => Schema::TYPE_PK,
            'title' => Schema::TYPE_STRING . ' NOT NULL',
            'content' => Schema::TYPE_TEXT,
        ]);
    }

    public function down()
    {
        $this->dropTable('news');
    }
}

信息: 并非所有迁移都是可逆的。例如,如果 up() 方法删除了表中的一行,您可能无法在 down() 方法中恢复此行。有时,您可能只是太懒得实现 down(),因为它并不常见于撤消数据库迁移。在这种情况下,您应该在 down() 方法中返回 false 以指示迁移不可逆。

基本迁移类 yii\db\Migration 通过 db 属性公开一个数据库连接。您可以使用它使用 数据库模式操作 中所述的方法来操作数据库模式。

在创建表或列时,应该使用抽象类型,而不是使用物理类型,这样您的迁移将独立于特定的 DBMS。 yii\db\Schema 类定义了一组常量来表示支持的抽象类型。这些常量的命名格式为 TYPE_<Name>。例如,TYPE_PK 指自动增量主键类型;TYPE_STRING 指字符串类型。当迁移应用于特定数据库时,抽象类型将被转换为相应的物理类型。在 MySQL 的情况下,TYPE_PK 将变为 int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,而 TYPE_STRING 变成 varchar(255)

使用抽象类型时,可以附加额外的约束。在上面的例子中, NOT NULL 附加到 Schema::TYPE_STRING 以指定该列不能为 null

信息: 抽象类型和物理类型之间的映射由每个具体 QueryBuilder 类中的 $typeMap 属性指定。

从 2.0.6 版本开始,您可以使用新引入的模式生成器,它提供了更方便的方式来定义列模式。因此,上面的迁移可以像下面这样编写

<?php

use yii\db\Migration;

class m150101_185401_create_news_table extends Migration
{
    public function up()
    {
        $this->createTable('news', [
            'id' => $this->primaryKey(),
            'title' => $this->string()->notNull(),
            'content' => $this->text(),
        ]);
    }

    public function down()
    {
        $this->dropTable('news');
    }
}

yii\db\SchemaBuilderTrait 的 API 文档中,可以找到用于定义列类型的可用方法列表。

信息: 生成的文件权限和所有权将由当前环境决定。这可能会导致无法访问文件。例如,当迁移在 Docker 容器中创建并在主机上编辑文件时,就会发生这种情况。在这种情况下,可以更改 MigrateController 的 newFileMode 和/或 newFileOwnership。例如,在应用程序配置中:`php <?php return [

  'controllerMap' => [
      'migrate' => [
          'class' => 'yii\console\controllers\MigrateController',
          'newFileOwnership' => '1000:1000', # Default WSL user id
          'newFileMode' => 0660,
      ],
  ],

]; `

生成迁移

从 2.0.7 版本开始,迁移控制台提供了一种便捷的方式来创建迁移。

如果迁移名称采用特殊形式,例如 create_xxx_tabledrop_xxx_table,那么生成的迁移文件将包含额外的代码,在本例中用于创建/删除表。在以下内容中,将描述此功能的所有变体。

创建表

yii migrate/create create_post_table

生成

/**
 * Handles the creation for table `post`.
 */
class m150811_220037_create_post_table extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post', [
            'id' => $this->primaryKey()
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function down()
    {
        $this->dropTable('post');
    }
}

要立即创建表字段,请通过 --fields 选项指定它们。

yii migrate/create create_post_table --fields="title:string,body:text"

生成

/**
 * Handles the creation for table `post`.
 */
class m150811_220037_create_post_table extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post', [
            'id' => $this->primaryKey(),
            'title' => $this->string(),
            'body' => $this->text(),
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function down()
    {
        $this->dropTable('post');
    }
}

您可以指定更多字段参数。

yii migrate/create create_post_table --fields="title:string(12):notNull:unique,body:text"

生成

/**
 * Handles the creation for table `post`.
 */
class m150811_220037_create_post_table extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post', [
            'id' => $this->primaryKey(),
            'title' => $this->string(12)->notNull()->unique(),
            'body' => $this->text()
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function down()
    {
        $this->dropTable('post');
    }
}

注意: 主键是自动添加的,默认情况下命名为 id。如果您想使用其他名称,您可以像 --fields="name:primaryKey" 那样显式指定它。

外键

从 2.0.8 版本开始,生成器支持使用 foreignKey 关键字进行外键操作。

yii migrate/create create_post_table --fields="author_id:integer:notNull:foreignKey(user),category_id:integer:defaultValue(1):foreignKey,title:string,body:text"

生成

/**
 * Handles the creation for table `post`.
 * Has foreign keys to the tables:
 *
 * - `user`
 * - `category`
 */
class m160328_040430_create_post_table extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post', [
            'id' => $this->primaryKey(),
            'author_id' => $this->integer()->notNull(),
            'category_id' => $this->integer()->defaultValue(1),
            'title' => $this->string(),
            'body' => $this->text(),
        ]);

        // creates index for column `author_id`
        $this->createIndex(
            'idx-post-author_id',
            'post',
            'author_id'
        );

        // add foreign key for table `user`
        $this->addForeignKey(
            'fk-post-author_id',
            'post',
            'author_id',
            'user',
            'id',
            'CASCADE'
        );

        // creates index for column `category_id`
        $this->createIndex(
            'idx-post-category_id',
            'post',
            'category_id'
        );

        // add foreign key for table `category`
        $this->addForeignKey(
            'fk-post-category_id',
            'post',
            'category_id',
            'category',
            'id',
            'CASCADE'
        );
    }

    /**
     * {@inheritdoc}
     */
    public function down()
    {
        // drops foreign key for table `user`
        $this->dropForeignKey(
            'fk-post-author_id',
            'post'
        );

        // drops index for column `author_id`
        $this->dropIndex(
            'idx-post-author_id',
            'post'
        );

        // drops foreign key for table `category`
        $this->dropForeignKey(
            'fk-post-category_id',
            'post'
        );

        // drops index for column `category_id`
        $this->dropIndex(
            'idx-post-category_id',
            'post'
        );

        $this->dropTable('post');
    }
}

foreignKey 关键字在列描述中的位置不会改变生成的代码。这意味着

  • author_id:integer:notNull:foreignKey(user)
  • author_id:integer:foreignKey(user):notNull
  • author_id:foreignKey(user):integer:notNull

都会生成相同的代码。

foreignKey 关键字可以接收一个括号中的参数,它将是为生成的外键关联的表名。如果未传递参数,则表名将从列名推断出来。

在上面的示例中,author_id:integer:notNull:foreignKey(user) 将生成一个名为 author_id 的列,该列与 user 表有外键关系,而 category_id:integer:defaultValue(1):foreignKey 将生成一个名为 category_id 的列,该列与 category 表有外键关系。

从 2.0.11 版本开始,foreignKey 关键字接受第二个参数,由空格分隔。它接受生成的外键关联的列名。如果未传递第二个参数,则列名将从表模式中获取。如果不存在模式,或未设置主键或主键是复合的,则将使用默认名称 id

删除表

yii migrate/create drop_post_table --fields="title:string(12):notNull:unique,body:text"

生成

class m150811_220037_drop_post_table extends Migration
{
    public function up()
    {
        $this->dropTable('post');
    }

    public function down()
    {
        $this->createTable('post', [
            'id' => $this->primaryKey(),
            'title' => $this->string(12)->notNull()->unique(),
            'body' => $this->text()
        ]);
    }
}

添加列

如果迁移名称采用 add_xxx_column_to_yyy_table 的形式,则文件内容将包含 addColumndropColumn 语句,这些语句是必需的。

要添加列

yii migrate/create add_position_column_to_post_table --fields="position:integer"

生成

class m150811_220037_add_position_column_to_post_table extends Migration
{
    public function up()
    {
        $this->addColumn('post', 'position', $this->integer());
    }

    public function down()
    {
        $this->dropColumn('post', 'position');
    }
}

您可以指定多个列,如下所示

yii migrate/create add_xxx_column_yyy_column_to_zzz_table --fields="xxx:integer,yyy:text"

删除列

如果迁移名称采用 drop_xxx_column_from_yyy_table 的形式,则文件内容将包含 addColumndropColumn 语句,这些语句是必需的。

yii migrate/create drop_position_column_from_post_table --fields="position:integer"

生成

class m150811_220037_drop_position_column_from_post_table extends Migration
{
    public function up()
    {
        $this->dropColumn('post', 'position');
    }

    public function down()
    {
        $this->addColumn('post', 'position', $this->integer());
    }
}

添加联接表

如果迁移名称采用 create_junction_table_for_xxx_and_yyy_tablescreate_junction_xxx_and_yyy_tables 的形式,则将生成创建联接表所需的代码。

yii migrate/create create_junction_table_for_post_and_tag_tables --fields="created_at:dateTime"

生成

/**
 * Handles the creation for table `post_tag`.
 * Has foreign keys to the tables:
 *
 * - `post`
 * - `tag`
 */
class m160328_041642_create_junction_table_for_post_and_tag_tables extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post_tag', [
            'post_id' => $this->integer(),
            'tag_id' => $this->integer(),
            'created_at' => $this->dateTime(),
            'PRIMARY KEY(post_id, tag_id)',
        ]);

        // creates index for column `post_id`
        $this->createIndex(
            'idx-post_tag-post_id',
            'post_tag',
            'post_id'
        );

        // add foreign key for table `post`
        $this->addForeignKey(
            'fk-post_tag-post_id',
            'post_tag',
            'post_id',
            'post',
            'id',
            'CASCADE'
        );

        // creates index for column `tag_id`
        $this->createIndex(
            'idx-post_tag-tag_id',
            'post_tag',
            'tag_id'
        );

        // add foreign key for table `tag`
        $this->addForeignKey(
            'fk-post_tag-tag_id',
            'post_tag',
            'tag_id',
            'tag',
            'id',
            'CASCADE'
        );
    }

    /**
     * {@inheritdoc}
     */
    public function down()
    {
        // drops foreign key for table `post`
        $this->dropForeignKey(
            'fk-post_tag-post_id',
            'post_tag'
        );

        // drops index for column `post_id`
        $this->dropIndex(
            'idx-post_tag-post_id',
            'post_tag'
        );

        // drops foreign key for table `tag`
        $this->dropForeignKey(
            'fk-post_tag-tag_id',
            'post_tag'
        );

        // drops index for column `tag_id`
        $this->dropIndex(
            'idx-post_tag-tag_id',
            'post_tag'
        );

        $this->dropTable('post_tag');
    }
}

从 2.0.11 版本开始,联接表的外键列名将从表模式中获取。如果表未在模式中定义,或未设置主键或主键是复合的,则将使用默认名称 id

事务性迁移

在执行复杂的数据库迁移时,确保每个迁移都成功或失败,这一点很重要,这样才能保持数据库的完整性和一致性。为了实现这个目标,建议您将每个迁移的数据库操作包含在一个 事务 中。

实现事务性迁移的更简单方法是将迁移代码放在 safeUp()safeDown() 方法中。这两个方法不同于 up()down(),因为它们隐式地包含在一个事务中。因此,如果这些方法中的任何操作失败,所有先前的操作将自动回滚。

在下面的例子中,除了创建 news 表之外,我们还向该表中插入了一行初始数据。

<?php

use yii\db\Migration;

class m150101_185401_create_news_table extends Migration
{
    public function safeUp()
    {
        $this->createTable('news', [
            'id' => $this->primaryKey(),
            'title' => $this->string()->notNull(),
            'content' => $this->text(),
        ]);

        $this->insert('news', [
            'title' => 'test 1',
            'content' => 'content 1',
        ]);
    }

    public function safeDown()
    {
        $this->delete('news', ['id' => 1]);
        $this->dropTable('news');
    }
}

请注意,通常情况下,当您在 safeUp() 中执行多个数据库操作时,您应该在 safeDown() 中反转它们的执行顺序。在上面的示例中,我们首先创建表,然后在 safeUp() 中插入一行;而在 safeDown() 中,我们首先删除行,然后删除表。

注意: 并非所有 DBMS 都支持事务。而且有些数据库查询不能放在事务中。有关一些示例,请参阅 隐式提交。如果是这种情况,您仍然应该实现 up()down(),而不是使用 safeUp()safeDown()

数据库访问方法

基本迁移类 yii\db\Migration 提供了一组方法,让您可以访问和操作数据库。您可能会发现这些方法的命名与 yii\db\Command 类提供的 DAO 方法 类似。例如,yii\db\Migration::createTable() 方法允许您创建一个新表,就像 yii\db\Command::createTable() 所做的那样。

使用 yii\db\Migration 提供的方法的好处是,您不需要显式创建 yii\db\Command 实例,并且每个方法的执行将自动显示有用的消息,告诉您执行了哪些数据库操作以及它们花费了多长时间。

以下是所有这些数据库访问方法的列表

信息: yii\db\Migration 不提供数据库查询方法。这是因为通常不需要显示有关从数据库检索数据的额外消息。这也是因为您可以使用功能强大的 Query Builder 来构建和运行复杂的查询。在迁移中使用 Query Builder 可能看起来像这样

// update status field for all users
foreach((new Query)->from('users')->each() as $user) {
    $this->update('users', ['status' => 1], ['id' => $user['id']]);
}

应用迁移

要将数据库升级到最新的结构,您应该使用以下命令应用所有可用的新迁移

yii migrate

此命令将列出迄今为止未应用的所有迁移。如果您确认要应用这些迁移,它将在每个新的迁移类中按其时间戳值顺序依次运行 up()safeUp() 方法。如果任何迁移失败,命令将退出而不应用其余迁移。

提示: 如果您在服务器上没有命令行,您可以尝试使用 web shell 扩展。

对于每个已成功应用的迁移,该命令将在名为 migration 的数据库表中插入一行,以记录迁移的成功应用。这将允许迁移工具识别哪些迁移已应用,哪些尚未应用。

信息: 迁移工具将在由命令的 db 选项指定的数据库中自动创建 migration 表。默认情况下,数据库由 db 应用程序组件 指定。

有时,您可能只想应用一个或几个新的迁移,而不是所有可用的迁移。您可以通过在运行命令时指定要应用的迁移数量来做到这一点。例如,以下命令将尝试应用接下来的三个可用迁移

yii migrate 3

您也可以通过以下格式之一使用 migrate/to 命令显式指定应将数据库迁移到的特定迁移

yii migrate/to 150101_185401                      # using timestamp to specify the migration
yii migrate/to "2015-01-01 18:54:01"              # using a string that can be parsed by strtotime()
yii migrate/to m150101_185401_create_news_table   # using full name
yii migrate/to 1392853618                         # using UNIX timestamp

如果存在任何未应用的早于指定迁移的迁移,它们都将在应用指定迁移之前应用。

如果指定的迁移已经应用,则将撤消任何以后应用的迁移。

撤消迁移

要撤消(撤销)之前已应用的一个或多个迁移,您可以运行以下命令

yii migrate/down     # revert the most recently applied migration
yii migrate/down 3   # revert the most 3 recently applied migrations

注意: 并非所有迁移都是可逆的。尝试撤消此类迁移将导致错误并停止整个撤消过程。

重做迁移

重做迁移意味着首先撤消指定的迁移,然后再次应用。这可以通过以下方式完成

yii migrate/redo        # redo the last applied migration
yii migrate/redo 3      # redo the last 3 applied migrations

注意: 如果迁移不可逆,则无法重做它。

刷新迁移

从 Yii 2.0.13 开始,您可以从数据库中删除所有表和外键,并从头开始应用所有迁移。

yii migrate/fresh       # truncate the database and apply all migrations from the beginning

列出迁移

要列出哪些迁移已应用,哪些未应用,您可以使用以下命令

yii migrate/history     # showing the last 10 applied migrations
yii migrate/history 5   # showing the last 5 applied migrations
yii migrate/history all # showing all applied migrations

yii migrate/new         # showing the first 10 new migrations
yii migrate/new 5       # showing the first 5 new migrations
yii migrate/new all     # showing all new migrations

修改迁移历史记录

有时,您可能只是想标记您的数据库已升级到特定迁移,而不是实际应用或撤消迁移。当您手动将数据库更改为特定状态并且您不希望以后重新应用该更改的迁移时,这种情况经常发生。您可以使用以下命令来实现此目标

yii migrate/mark 150101_185401                      # using timestamp to specify the migration
yii migrate/mark "2015-01-01 18:54:01"              # using a string that can be parsed by strtotime()
yii migrate/mark m150101_185401_create_news_table   # using full name
yii migrate/mark 1392853618                         # using UNIX timestamp

该命令将修改 migration 表,通过添加或删除某些行来指示数据库已将迁移应用到指定的迁移。此命令不会应用或撤消任何迁移。

自定义迁移

有几种方法可以自定义迁移命令。

使用命令行选项

迁移命令附带了一些命令行选项,可用于自定义其行为

  • interactive: 布尔值(默认为 true),指定是否以交互模式执行迁移。当这为 true 时,将在命令执行某些操作之前提示用户。如果您在后台进程中使用该命令,则可能希望将其设置为 false

  • migrationPath: 字符串 | 数组(默认为 @app/migrations),指定存储所有迁移类文件的目录。这可以指定为目录路径或路径 别名。请注意,目录必须存在,否则命令可能会触发错误。从 2.0.12 版开始,可以指定一个数组以从多个来源加载迁移。

  • migrationTable: 字符串(默认为 migration),指定用于存储迁移历史记录信息的数据库表的名称。如果该表不存在,该命令将自动创建它。您也可以使用结构 version varchar(255) primary key, apply_time integer 手动创建它。

  • db: 字符串(默认为 db),指定数据库 应用程序组件 的 ID。它表示将使用此命令迁移的数据库。

  • templateFile: 字符串(默认为 @yii/views/migration.php),指定用于生成迁移类文件骨架的模板文件的路径。这可以指定为文件路径或路径 别名。模板文件是一个 PHP 脚本,您可以在其中使用名为 $className 的预定义变量来获取迁移类名。

  • generatorTemplateFiles: 数组(默认为 `[

      'create_table' => '@yii/views/createTableMigration.php',
      'drop_table' => '@yii/views/dropTableMigration.php',
      'add_column' => '@yii/views/addColumnMigration.php',
      'drop_column' => '@yii/views/dropColumnMigration.php',
      'create_junction' => '@yii/views/createTableMigration.php'
    

    ]`), 指定用于生成迁移代码的模板文件。有关更多详细信息,请参阅“生成迁移”。

  • fields: 用于创建迁移代码的列定义字符串数组。默认为 []。每个定义的格式为 COLUMN_NAME:COLUMN_TYPE:COLUMN_DECORATOR。例如,--fields=name:string(12):notNull 生成一个大小为 12 的字符串列,它不是 null

以下示例显示了如何使用这些选项。

例如,如果我们要迁移一个 forum 模块,其迁移文件位于模块的 migrations 目录中,我们可以使用以下命令

# migrate the migrations in a forum module non-interactively
yii migrate --migrationPath=@app/modules/forum/migrations --interactive=0

全局配置命令

而不是每次运行迁移命令时都输入相同的选项值,您可以在应用程序配置中为所有选项配置一次,如下所示

return [
    'controllerMap' => [
        'migrate' => [
            'class' => 'yii\console\controllers\MigrateController',
            'migrationTable' => 'backend_migration',
        ],
    ],
];

有了上述配置,每次运行迁移命令时,都会使用 backend_migration 表来记录迁移历史记录。您不再需要通过 migrationTable 命令行选项指定它。

命名空间迁移

从 2.0.10 开始,您可以对迁移类使用命名空间。您可以通过 migrationNamespaces 指定迁移命名空间的列表。对迁移类使用命名空间允许您对迁移使用多个源位置。例如

return [
    'controllerMap' => [
        'migrate' => [
            'class' => 'yii\console\controllers\MigrateController',
            'migrationPath' => null, // disable non-namespaced migrations if app\migrations is listed below
            'migrationNamespaces' => [
                'app\migrations', // Common migrations for the whole application
                'module\migrations', // Migrations for the specific project's module
                'some\extension\migrations', // Migrations for the specific extension
            ],
        ],
    ],
];

注意: 从不同命名空间应用的迁移将创建一个 **单个** 迁移历史记录,例如,您可能无法仅应用或撤消特定命名空间的迁移。

在操作命名空间迁移时:创建新的、撤消等等,您应该在迁移名称之前指定完整命名空间。请注意,反斜杠 (\) 符号通常被视为 shell 中的特殊字符,因此您需要对其进行适当转义以避免 shell 错误或不正确行为。例如

yii migrate/create app\\migrations\\CreateUserTable

注意: 通过 migrationPath 指定的迁移不能包含命名空间,命名空间迁移只能通过 yii\console\controllers\MigrateController::$migrationNamespaces 属性应用。

从 2.0.12 版开始,migrationPath 属性还接受一个数组,用于指定包含无命名空间迁移的多个目录。这主要是在现有项目中使用,这些项目从不同位置使用迁移。这些迁移主要来自外部来源,例如由其他开发人员开发的 Yii 扩展,这些扩展在开始使用新方法时无法轻松更改为使用命名空间。

生成命名空间迁移

命名空间迁移遵循“CamelCase”命名模式 M<YYMMDDHHMMSS><Name>(例如 M190720100234CreateUserTable)。生成此类迁移时,请记住表名将从“CamelCase”格式转换为“下划线”。例如

yii migrate/create app\\migrations\\DropGreenHotelTable

在命名空间 app\migrations 内生成迁移,删除表 green_hotel,以及

yii migrate/create app\\migrations\\CreateBANANATable

在命名空间 app\migrations 内生成迁移,创建表 b_a_n_a_n_a

如果表的名称是混合大小写(如 studentsExam),您需要在名称前加上下划线

yii migrate/create app\\migrations\\Create_studentsExamTable

这将在命名空间 app\migrations 内生成迁移,创建表 studentsExam

分离的迁移

有时,对所有项目迁移使用单个迁移历史记录不可取。例如:您可能安装了一些“博客”扩展,它包含完全独立的功能并包含自己的迁移,这些迁移不应影响专门用于主要项目功能的迁移。

如果您希望多个迁移彼此完全独立地应用和跟踪,您可以配置多个迁移命令,这些命令将使用不同的命名空间和迁移历史记录表

return [
    'controllerMap' => [
        // Common migrations for the whole application
        'migrate-app' => [
            'class' => 'yii\console\controllers\MigrateController',
            'migrationNamespaces' => ['app\migrations'],
            'migrationTable' => 'migration_app',
            'migrationPath' => null,
        ],
        // Migrations for the specific project's module
        'migrate-module' => [
            'class' => 'yii\console\controllers\MigrateController',
            'migrationNamespaces' => ['module\migrations'],
            'migrationTable' => 'migration_module',
            'migrationPath' => null,
        ],
        // Migrations for the specific extension
        'migrate-rbac' => [
            'class' => 'yii\console\controllers\MigrateController',
            'migrationPath' => '@yii/rbac/migrations',
            'migrationTable' => 'migration_rbac',
        ],
    ],
];

请注意,要同步数据库,您现在需要运行多个命令,而不是一个命令

yii migrate-app
yii migrate-module
yii migrate-rbac

迁移多个数据库

默认情况下,迁移将应用到由 db 应用程序组件 指定的同一数据库。如果您希望它们应用到不同的数据库,您可以指定 db 命令行选项,如下所示,

yii migrate --db=db2

上面的命令将迁移应用于 db2 数据库。

有时,您可能希望将一些迁移应用到一个数据库,而将另一些迁移应用到另一个数据库。要实现此目标,在实现迁移类时,您应该显式指定迁移将使用的 DB 组件 ID,如下所示

<?php

use yii\db\Migration;

class m150101_185401_create_news_table extends Migration
{
    public function init()
    {
        $this->db = 'db2';
        parent::init();
    }
}

上面的迁移将应用于 db2,即使您通过 db 命令行选项指定了不同的数据库。请注意,迁移历史记录仍将在由 db 命令行选项指定的数据库中记录。

如果您有多个使用同一数据库的迁移,建议您创建一个具有上述 init() 代码的基迁移类。然后,每个迁移类都可以从这个基类继承。

提示:除了设置 db 属性,您还可以通过在迁移类中创建新的数据库连接来操作不同的数据库。然后使用这些连接的 DAO 方法 来操作不同的数据库。

另一种迁移多个数据库的策略是将不同数据库的迁移放在不同的迁移路径中。然后您可以使用以下命令分别迁移这些数据库

yii migrate --migrationPath=@app/migrations/db1 --db=db1
yii migrate --migrationPath=@app/migrations/db2 --db=db2
...

第一个命令将应用 @app/migrations/db1 中的迁移到 db1 数据库,第二个命令将应用 @app/migrations/db2 中的迁移到 db2,以此类推。

发现错别字或您认为此页面需要改进?
在 github 上编辑 !