php yii mysql 导出_[Yii2笔记]019 为数据库创建迁移和生成迁移(migration)

说明

学习Yii Framework 2(易2框架)的过程是漫长的,也是充满乐趣的,以下是我学习Yii2框架时对官网英文资料(请参见原文网址)的翻译和代码实现,提供了较完整的代码,供你参考。不妥之处,请多多指正!

原文网址:

http://www.yiiframework.com/doc-2.0/guide-db-migrations.html

http://www.yiiframework.com/doc-2.0/guide-db-migrations.html#creating-migrations

1、Creating Migrations(创建迁移)

http://www.yiiframework.com/doc-2.0/guide-db-migrations.html#generating-migrations

2、Generating Migrations(生成迁移)

本文主题:为数据库创建迁移和生成迁移(migration)

在开发和维护数据库驱动的应用过程中,数据库的结构与源代码的开发同步更新。例如,在应用开发的过程中,新建了一张表,在应用部署到生产环境后,发现需要为这张表创建一个索引以提升查询性能,等等。因为数据库结构改变后需要源代码随之而改变,Yii支持此类数据库迁移特征,这样你就可以用数据库迁移的形式追踪数据库的变化,也就是与源代码同步的版本控制。

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

1、Tim创建了一个新的迁移(例如,创建了一张新表,更改了一个字段定义等)

2、Tim提交了新迁移到源代码控制系统中(如Git,Mercurial)

3、Doug从源码控制系统中更新了他的仓库,并接收了新的迁移

4、Doug应用新迁移到他本地的开发数据库,也就是同步了Tim所做的数据库变更到他自己的数据库中。

以下步骤展示了如何部署一个新的数据库迁移版本到生产环境:

1、Scott为项目仓库的新数据库迁移创建了一个版本标签。

2、Scott在生产服务器上更新源码到新版本标签。

3、Scott应用所累积的数据库迁移到生产数据库中。

Yii提供了一组迁移命令工具让你可以:

1、创建新迁移

2、应用迁移

3、恢复迁移

4、再次应用迁移

5、显示迁移历史和状态

所有这些工具都可以通过命令yii migrate来使用,本章节我们将描述使用这些工具完成各项任务的细节,你可以使用帮助命令yii help migrate获取每个工具的用法。

小贴士:迁移不仅影响到数据库的schema,还将调整原有数据以适应新迁移,创建RBAC分层结构或者清除缓存。

1、创建迁移(Creating Migrations)

//table//migrate

要创建一个新的迁移,运行以下命令:

yii migrate/create

必填参数name对新迁移进行了概述,例如,如果本次迁移是创建了一个新表news,你可以使用名称create_news_table,并运行以下命令:

D:\phpwork\basic>yii migrate/create create_news_table

Yii Migration Tool (based on Yii v2.0.8)

Create new migration 'D:\phpwork\basic/migrations\m170313_082453_create_news_tab

le.php'? (yes|no) [no]:y

New migration created successfully.

D:\phpwork\basic>

注意:因为name参数将被用于创建迁移类的名称,所以它只能包含字母,数字和下划线。

以上命令将会在@app/migrations目录下创建一个新的名为m150101_185401_create_news_table.php的PHP类文件。此文件主要是定义了一个迁移类m150101_185401_create_news_table框架代码,代码如下:

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_,这里:

,指迁移创建命令运行时的UTC时间

,是你在运行命令时提供的name参数值

在迁移类中,你需要在up()方法中编写代码,以明确在数据库结构上做出哪些改变。你可能也想要在down()方法中编写代码,以恢复那些被up()做过的修改。当你做此迁移升级数据库时,up()方法将被调用;当需要数据库降回去时,将调用down()方法。以下代码展示了,创建news表时,你需要去完成的迁移类:

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属性的数据库连接,你可以使用它操作数据库shcema,这些方法在Working with Database Schema章节中已描述:

http://www.yiiframework.com/doc-2.0/guide-db-dao.html#database-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以定义此列不能为空(null)。

信息:抽象类型与物理类型之间的对应关系在每个具体的QueryBuilder类中由$typeMap 属性来定义。

例如:mysql的$typeMap 定义:

D:\phpwork\basic\vendor\yiisoft\yii2\db\mysql\QueryBuilder.php

自2.0.6版起,你可以使用新引入的结构构建器,它提供了定义列结构更为简便的方法。上例所示的迁移就可以改写为:

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');

}

}

2、生成迁移(Generating Migrations)

自2.0.7版本开始,迁移控制台提供更加方便的方法去创建迁移。

如果迁移名称是特定形式,例如create_xxx_table或drop_xxx_table,那么生成的迁移文件将包含额外的代码,也就是创建或删除表。接下来将描述此特征的各种变化:

//Create Table(创建表)

yii migrate/create create_post_table

//实际使用的是“yii migrate/create create_post”,如下:

D:\phpwork\basic>yii migrate/create create_post

Yii Migration Tool (based on Yii v2.0.8)

Create new migration 'D:\phpwork\basic/migrations\m170314_032934_create_post.php

'? (yes|no) [no]:y

New migration created successfully.

D:\phpwork\basic>

//将生成代码:

/**

* Handles the creation for table `post`.

*/

class m150811_220037_create_post extends Migration{

/**

* @inheritdoc

*/

public function up(){

$this->createTable('post', [

'id' => $this->primaryKey()

]);

}

/**

* @inheritdoc

*/

public function down(){

$this->dropTable('post');

}

}

通过--fields选项可以直接定义表的字段:

D:\phpwork\basic>yii migrate/create create_post --fields="title:string,body:text"

Yii Migration Tool (based on Yii v2.0.8)

Create new migration 'D:\phpwork\basic/migrations\m170314_033234_create_post.php'? (yes|no) [no]:y

New migration created successfully.

D:\phpwork\basic>

//生成的代码:

D:\phpwork\basic\migrations\m170314_033234_create_post.php

use yii\db\Migration;

/**

* Handles the creation for table `post`.

*/

class m170314_033234_create_post 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');

}

}

//也可以创建更多的字段属性

D:\phpwork\basic>yii migrate/create create_post --fields="title:string(12):notNUll:unique,body:text"

Yii Migration Tool (based on Yii v2.0.8)

Create new migration 'D:\phpwork\basic/migrations\m170314_033848_create_post.php'? (yes|no) [no]:y

New migration created successfully.

D:\phpwork\basic>

//将生成

D:\phpwork\basic\migrations\m170314_033848_create_post.php

use yii\db\Migration;

/**

* Handles the creation for table `post`.

*/

class m170314_033848_create_post 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"

//Foreign keys(外键)

从2.0.8开始,生成器支持使用foreignKey生成外键:

D:\phpwork\basic>yii migrate/create create_post --fields="author_id:integer:notNull:foreignKey(user),category_id:integer:defaultValue(1):foreignKey,title:string(12):notNUll:unique,body:text"

Yii Migration Tool (based on Yii v2.0.8)

Create new migration 'D:\phpwork\basic/migrations\m170314_035136_create_post.php'? (yes|no) [no]:y

New migration created successfully.

D:\phpwork\basic>

//将生成:

D:\phpwork\basic\migrations\m170314_035136_create_post.php

use yii\db\Migration;

/**

* Handles the creation for table `post`.

* Has foreign keys to the tables:

*

* - `user`

* - `category`

*/

class m170314_035136_create_post 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(12)->notNUll()->unique(),

'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:foreighKey(user):integer:notNull

将会产生同样的代码。

foreignKey关键字可以在括号中带一个参数,此参数是要生成的外键所关联的表名称,如果没有传递参数,将从列名中推演出表名称。

在上例中auth_id:integer:notNull:foreignKey(user)将生成名为author_id的字段,此字段有一个user表的外键;category_id:integer:defaultValue(1):foreignKey将生成名为category_id的字段,此字段有一个category的外键。

从2.0.11开始,foreignKey关键字可以接收第2个参数,使用空格分隔,它可以指定生成的外键所关联的列名称,如果第2参数被忽略,列名称将从表结构(table schema)中获取,如果表结构没有存在,主键没有设置或是复合主键,将使用默认名称:id。

//Drop Table(删除表)

D:\phpwork\basic>yii migrate/create drop_post --fields="title:string(12):noNull:unique,body:text"

Yii Migration Tool (based on Yii v2.0.8)

Create new migration 'D:\phpwork\basic/migrations\m170314_054507_drop_post.php'? (yes|no) [no]:y

New migration created successfully.

D:\phpwork\basic>

//将生成:

D:\phpwork\basic\migrations\m170314_054507_drop_post.php

use yii\db\Migration;

/**

* Handles the dropping for table `post`.

*/

class m170314_054507_drop_post extends Migration{

/**

* @inheritdoc

*/

public function up(){

$this->dropTable('post');

}

/**

* @inheritdoc

*/

public function down(){

$this->createTable('post', [

'id' => $this->primaryKey(),

'title' => $this->string(12)->noNull()->unique(),

'body' => $this->text(),

]);

}

}

//Add Column(添加列)//column

如果迁移名称样式是add_xxx_column_to_yyy,将在生成的文件中包含addColumn和dropColumn语句。

D:\phpwork\basic>yii migrate/create add_position_column_to_post --fields="position:integer"

Yii Migration Tool (based on Yii v2.0.8)

Create new migration 'D:\phpwork\basic/migrations\m170314_054954_add_position_column_to_post.php'? (yes|no) [no]:y

New migration created successfully.

D:\phpwork\basic>

//将生成:

D:\phpwork\basic\migrations\m170314_054954_add_position_column_to_post.php

use yii\db\Migration;

/**

* Handles adding position_column to table `post`.

*/

class m170314_054954_add_position_column_to_post extends Migration{

/**

* @inheritdoc

*/

public function up(){

$this->addColumn('post', 'position', $this->integer());

}

/**

* @inheritdoc

*/

public function down(){

$this->dropColumn('post', 'position');

}

}

//一次添加多个字段:

D:\phpwork\basic>yii migrate/create add_position_column_to_post --fields="position:integer,click:integer"

//Drop Column(删除列)

如果迁移名称样式是drop_xxx_column_from_yyy,生成的文件将包含dropColumn和addColumn语句。

D:\phpwork\basic>yii migrate/create drop_position_column_from_post --fields="position:integer"

Yii Migration Tool (based on Yii v2.0.8)

Create new migration 'D:\phpwork\basic/migrations\m170314_060321_drop_position_column_from_post.php'? (yes|no) [no]:y

New migration created successfully.

D:\phpwork\basic>

//将生成:

D:\phpwork\basic\migrations\m170314_060321_drop_position_column_from_post.php

use yii\db\Migration;

/**

* Handles dropping position_column from table `post`.

*/

class m170314_060321_drop_position_column_from_post extends Migration{

/**

* @inheritdoc

*/

public function up(){

$this->dropColumn('post', 'position');

}

/**

* @inheritdoc

*/

public function down(){

$this->addColumn('post', 'position', $this->integer());

}

}

//Add Junction Table(添加Junction表)

如果迁移名称样式是create_junction_table_for_xxx_and_yyy_tables或create_junction_xxx_and_yyy_tables,那么创建junction表的代码将会被生成。

D:\phpwork\basic>yii migrate/create create_junction_for_post_and_tag --fields="created_at:dateTime"

Yii Migration Tool (based on Yii v2.0.8)

Create new migration 'D:\phpwork\basic/migrations\m170314_060957_create_junction_for_post_and_tag.php'? (yes|no) [no]:y

New migration created successfully.

D:\phpwork\basic>

//将生成:

D:\phpwork\basic\migrations\m170314_060957_create_junction_for_post_and_tag.php

use yii\db\Migration;

/**

* Handles the creation for table `for_post_tag`.

* Has foreign keys to the tables:

*

* - `for_post`

* - `tag`

*/

class m170314_060957_create_junction_for_post_and_tag extends Migration{

/**

* @inheritdoc

*/

public function up(){

$this->createTable('for_post_tag', [

'for_post_id' => $this->integer(),

'tag_id' => $this->integer(),

'created_at' => $this->dateTime(),

'PRIMARY KEY(for_post_id, tag_id)',

]);

// creates index for column `for_post_id`

$this->createIndex(

'idx-for_post_tag-for_post_id',

'for_post_tag',

'for_post_id'

);

// add foreign key for table `for_post`

$this->addForeignKey(

'fk-for_post_tag-for_post_id',

'for_post_tag',

'for_post_id',

'for_post',

'id',

'CASCADE'

);

// creates index for column `tag_id`

$this->createIndex(

'idx-for_post_tag-tag_id',

'for_post_tag',

'tag_id'

);

// add foreign key for table `tag`

$this->addForeignKey(

'fk-for_post_tag-tag_id',

'for_post_tag',

'tag_id',

'tag',

'id',

'CASCADE'

);

}

/**

* @inheritdoc

*/

public function down(){

// drops foreign key for table `for_post`

$this->dropForeignKey(

'fk-for_post_tag-for_post_id',

'for_post_tag'

);

// drops index for column `for_post_id`

$this->dropIndex(

'idx-for_post_tag-for_post_id',

'for_post_tag'

);

// drops foreign key for table `tag`

$this->dropForeignKey(

'fk-for_post_tag-tag_id',

'for_post_tag'

);

// drops index for column `tag_id`

$this->dropIndex(

'idx-for_post_tag-tag_id',

'for_post_tag'

);

$this->dropTable('for_post_tag');

}

}

自2.0.11版本开始,Junction表的外键列名称从表结构中获取,如果结构中没有定义表,或主键没有设置或是复合主键,将使用默认值:id。

//Transactional Migrations(事务化迁移)

当执行复杂的DB迁移时,确保每次迁移是整体成功或失败是非常重要的,这样使得数据库能够保持完整性和一致性。要实现这个目标,推荐你将每次迁移相关的数据库操作封装到一个事务中去。

一个实现事务化迁移更简单的方法是将迁移代码主在safeUp()和safeDown()方法中,这两个方法不同于up()和down()之处在于,它们是完全封装于事务中的。因此,如果在这些方法中有任何失败,之前的所有操作都将被自动回滚。

在下例中,除了创建一个news表外,我们还插入了一个初始化行记录到这个表中:

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()方法中执行多个DB操作时,你应该在safeDown()中掉转它们的执行顺序。在上例中我们首先在safeUp()中创建了表然后插入了一行记录,在safeDown()中我们先删除了行记录然后再删除表。

注意:不是所有的DBMS都支持事务,一些数据查询也不能被放到事务中来,更多实例,请参考隐式提交(implicit commit):

https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html

在此种情况下,你应该使用up()或down()。

//数据库存取方法(Database Accessing Methods)

基础迁移类yii\db\Migration提供了一组从数据库获取和操作的方法。你会发现这些方法的命名与yii\db\Command类提供的DAO方法相似。例如:yii\db\Migration::createTable()方法允许你创建一个新表,与yii\db\Command::createTable()类似。

使用yii\db\Migration提供的方法的好处是,你无需明确创建yii\db\Command实例,每个方法执行时都会自动显示有用的信息,告诉你哪个数据库操作已完成,还需要多长时间。

以下列出了所有的数据库存取操作方法:

execute(),执行一个SQL语句

insert(),插入一行

batchInsert(),插入多行

update(),更新多行记录

delete(),删除多行记录

createTable(),创建一个表

renameTable(),重命名一个表

dropTable(),删除一个表

truncateTable(),删除表中的所有记录

addColumn(),添加一列

renameColumn(),重命名列

dropColumn(),删除一列

alterColumn(),修改列关系(外键之类的)

addPrimaryKey(),添加一个主键

dropPrimaryKey(),删除一个主键

addForeignKey(),添加一个外键

dropForeignKey(),删除一个外键

createIndex(),创建一个索引

dropIndex(),删除一个索引

addCommentOnColumn(),为列添加注释

dropCommentFromColumn(),删除列注释

addCommentOnTable(),为表添加注释

dropCommentFromTable(),删除列注释

信息:yii\db\Migration没有提供数据库查询方法,这是因为你从数据库取回数据时无需显示额外的信息,也因为你可以使用Query Builder构建和运行更为复杂的查询语句。

注意:当使用迁移处理数据时,你可能发现使用你的Active Record类做此项操作更好使,因为在AR中已经有了实现逻辑。记住,迁移中编写的代码是永远不变的,与此不同的是,应用逻辑将随着业务的改变而改变。在迁移代码中使用AR类,如果AR层逻辑被修改后,将导致现存迁移的意外终止,正因如此,迁移应保持独立,以与其他应用逻辑如AR类相分离。

(全文完)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值