Yii2 数据库迁移


Yii2 数据库迁移


引例

生成文件:

php yii migrate/create Notice

写入内容:

<?php

use yii\db\Migration;

/**
 * Class m210901_073337_Notice
 */
class m210901_073337_Notice extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function safeUp()
    {
        // 消息
        $this->createTable('notice', [
            'id'             => $this->primaryKey(),
            'user_id'        => $this->integer()->notNull()->defaultValue(0)->comment('创建人id'),
            'application_id' => $this->integer()->notNull()->defaultValue(0)->comment('应用id'),
            'type'           => $this->tinyInteger()->notNull()->defaultValue(0)->comment('消息类型'),
            'status'         => $this->tinyInteger()->notNull()->defaultValue(0)->comment('状态,草稿:0,正式:1'),
            'publish_type'   => $this->tinyInteger()->notNull()->defaultValue(0)->comment('发布类型,立即发布:0,定时发布:1'),
            'publish_at'     => $this->integer()->notNull()->defaultValue(0)->comment('发布时间'),
            'create_at'      => $this->integer()->notNull()->defaultValue(0)->comment('创建时间'),
            'update_at'      => $this->integer()->notNull()->defaultValue(0)->comment('更新时间'),
        ]);
        $this->createIndex('idx_application_id', 'notice', ['application_id']);

        $this->addColumn('department', 'status', $this->tinyInteger()->notNull()->defaultValue(10)->comment('状态,10:正常,20:禁用,99:删除'));
    }

    /**
     * {@inheritdoc}
     */
    public function safeDown()
    {
        $this->dropTable('notice');
               
        $this->dropColumn('department', 'status');
    }

    /*
    // Use up()/down() to run migration code without a transaction.
    public function up()
    {

    }

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

        return false;
    }
    */
}

迁移:

php yii migrate

正文

在开发和维护一个数据库驱动的应用程序时, 数据库的结构会像代码一样不断演变。 例如,在开发应用程序的过程中, 会增加一张新表且必须得加进来; 在应用程序被部署到生产环境后,需要建立一个索引来提高查询的性能等等。 因为一个数据库结构发生改变的时候源代码也经常会需要做出改变, Yii 提供了一个 数据库迁移 功能, 该功能可以记录数据库的变化, 以便使数据库和源代码一起受版本控制。

如下的步骤向我们展示了数据库迁移工具是如何为开发团队所使用的:

Tim 创建了一个新的迁移对象(例如,创建一张新表,改变字段的定义等)。
Tim 将这个新的迁移对象提交到代码管理系统(例如,Git,Mercurial)。
Doug 从代码管理系统当中更新版本并获取到这个新的迁移对象。
Doug 把这个迁移对象提交到本地的开发数据库当中, 这样一来,Doug 同步了 Tim 所做的修改。

如下的步骤向我们展示了如何发布一个附带数据库迁移的新版本到生产环境当中:

Scott 为一个包含数据库迁移的项目版本创建了一个发布标签。
Scott 把发布标签的源代码更新到生产环境的服务器上。
Scott 把所有的增量数据库迁移提交到生产环境数据库当中。

Yii 提供了一整套的迁移命令行工具,通过这些工具你可以:

创建新的迁移;
提交迁移;
恢复迁移;
重新提交迁移;
展示迁移历史和状态。

所有的这些工具都可以通过 yii migrate 命令来进行操作。 在这一章节,我们将详细的介绍如何使用这些工具来完成各种各样的任务。 你也可以通过 yii help migrate 命令来获取每一种工具的具体使用方法。

  • 提示: 迁移不仅仅只作用于数据库表, 它同样会调整现有的数据来适应新的表单、创建 RBAC 分层、又或者是清除缓存。

  • 注意: 当你使用迁移来操作数据时,你会发现使用 活动记录 类 很有帮助,因为一些逻辑已经在那里实现了。 然而别忘了,相比于天生保持恒定不变的迁移类中的代码,程序逻辑是随时变化的。 所以当你在迁移中使用活动记录类时, 活动记录层中逻辑的变化可能会意外打断现有的迁移。 基于这个原因, 迁移代码应该保持独立于其他程序逻辑,比如活动记录类。

创建迁移

使用如下命令来创建一个新的迁移:

yii migrate/create

必填参数 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> 指执行创建迁移命令的 UTC 时间。
<Name> 和你执行命令时所带的 name 参数值相同。

在迁移类当中,你应当在 up() 方法中编写改变数据库结构的代码。 你可能还需要在 down() 方法中编写代码来恢复由 up() 方法所做的改变。 当你通过 migration 升级数据库时, up() 方法将会被调用,反之, down() 将会被调用。 如下代码展示了如何通过迁移类来创建一张 news 表:


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

class m150101_185401_create_news_table extends \yii\db\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 来表明这个 migration 是无法恢复的。

migration 的基类 yii\db\Migration 通过 db 属性来连接数据库。 你可以通过 操作数据库模式(schema) 章节中所描述的那些方法来操作数据库模式(schema)。

当你创建一张表或者一个字段的时候,你应该使用 抽象类型 而不是 实体类型, 这样一来你的迁移对象就可以从特定的 DBMS 当中抽离出来。 yii\db\Schema 类定义了一整套可用的抽象类型常量。这些常量的格式为 TYPE_。 例如,TYPE_PK 指代自增主键类型;TYPE_STRING 指代字符串类型。 当迁移对象被提交到某个特定的数据库的时候, 这些抽象类型将会被转换成相对应的实体类型。 以 MySQL 为例,TYPE_PK 将会变成 int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 而 TYPE_STRING 则变成 varchar(255)。

在使用抽象类型的时候,你可以添加额外的约束条件。在上面的例子当中, NOT NULL 被添加到 Schema::TYPE_STRING 当中来指定该字段不能为空。

提示: 抽象类型和实体类型之间的映射关系是由每个具体的 QueryBuilder 类当中的 $typeMap 属性所指定的。

从 2.0.6 版本开始,你可以使用能提供更便捷的方法定义字段模式(schema)的新模式(schema)构建器。 这样上面的迁移就可以写成这样:

<?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 文档中查到。

生成迁移

从 2.0.7 版本开始,迁移终端提供了一种创建迁移的便捷方法。

如果迁移对象的名称遵循某种特定的格式,比如 create_xxx 或者 drop_xxx, 那么生成的迁移代码中将包含创建/删除表的额外代码。 在下文中将描述该特型的所有变型。

提交迁移

为了将数据库升级到最新的结构,你应该使用如下命令来提交所有新的迁移:

yii migrate

这条命令会列出迄今为止所有未提交的迁移。如果你确定你需要提交这些迁移, 它将会按照类名当中的时间戳的顺序, 一个接着一个的运行每个新的迁移类里面的 up() 或者是 safeUp() 方法。 如果其中任意一个迁移提交失败了, 那么这条命令将会退出并停止剩下的那些还未执行的迁移。

  • 提示: 如果你的服务器没有命令行, 你可以尝试 web shell 这个扩展。

对于每一个成功提交的迁移,这条命令都会在一个叫做 migration 的数据库表中插入一条包含应用程序成功提交迁移的记录, 该记录将帮助迁移工具判断哪些迁移已经提交,哪些还没有提交。

  • 信息: 迁移工具将会自动在数据库当中创建 migration 表, 该数据库是在该命令的 db 选项当中指定的。 默认情况下,是由 db application component 指定的。
CREATE TABLE `migration` (
  `version` varchar(180) COLLATE utf8mb4_bin NOT NULL,
  `apply_time` int(11) DEFAULT NULL,
  PRIMARY KEY (`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

有时,你可能只需要提交一个或者少数的几个迁移, 你可以使用该命令指定需要执行的条数,而不是执行所有的可用迁移。 例如,如下命令将会尝试提交前三个可用的迁移:

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() 使用一个可以被 strtotime() 解析的字符串
yii migrate/to m150101_185401_create_news_table   # using full name 使用全名
yii migrate/to 1392853618                         # using UNIX timestamp 使用 UNIX 时间戳

如果在指定要提交的迁移前面还有未提交的迁移,那么在执行这个被指定的迁移之前, 这些还未提交的迁移会先被提交。

如果被指定提交的迁移在之前已经被提交过,那么在其之后的那些迁移将会被还原。

还原迁移

你可以使用如下命令来还原其中一个或多个以前被提交过的迁移:

yii migrate/down     # revert the most recently applied migration 还原最近一次提交的迁移
yii migrate/down 3   # revert the most 3 recently applied migrations 还原最近三次提交的迁移
  • 注意: 并不是所有的迁移都能被还原。 尝试还原这类迁移将可能导致报错甚至是终止所有的还原进程。

重做迁移

刷新迁移

列出迁移

修改迁移历史

自定义迁移

迁移多个数据库






参考资料

首页 文档 Yii 2.0 权威指南 配合数据库工作(Working with Databases): 数据库迁移(Migrations) https://www.yiichina.com/doc/guide/2.0/db-migrations


返回