yii2.0数据库迁移教程【多个数据库同时同步数据】


Posted in PHP onOctober 08, 2016

本文讲述了yii2.0数据库迁移的方法。分享给大家供大家参考,具体如下:

创建迁移

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

yii migrate/create <name>

必填参数 name 的作用是对新的迁移做一个简要的描述。例如,如果这个迁移是用来往多个数据库同一张表  ( 假设每个数据库都有news表 )   添加字段的,那么你可以使用addColumn_news (该名称自定义)这个名称并运行如下命令:

yii migrate/create addColumn_news

注意:因为 name 参数会被用来生成迁移的类名的一部分,所以该参数应当只包含字母、数字和下划线。

如上命令将会在 @app/migrations 目录下创建一个新的名为 m150101_185401_addColumn_news.php 的 PHP 类文件。该文件包含如下的代码,它们用来声明一个迁移类 m150101_185401_addColumn_news,并附有代码框架:

<?php
use yii\db\Schema;
use yii\db\Migration;
class m150101_185401_addColumn_news extends Migration
{
//createDbs 该方法是获取数据库对象返回
private function createDbs(){
  $dbs = [];
  $dbs_info =\Yii::$app->params['db'];
  foreach($dbs_info as $k=>$v){
    $dbs[$k] = \Yii::createObject($v);
  }
  return $dbs;
}
//up() 该方法是往不同的数据库的news表添加 name,nickname,age,sex,site_id等字段
public function up()
{
  $dbs = $this->createDbs();
  foreach($dbs as $v){   //《------遍历讲字段同时添加到不同的数据库中
    $this->db=$v;
    $this->addColumn('{{%news}}','name','varchar(20)');
    $this->addColumn('{{%news}}','nickname','varchar(20)');
    $this->addColumn('{{%news}}','age','int(3)');
    $this->addColumn('{{%news}}','sex','int(1)');
    $this->addColumn('{{%news}}','site_id','int(5)');
  }
}
//down()  该方法与up()方法相反,是删除字段的意思
public function down()
{
  $dbs = $this->createDbs();
  foreach($dbs as $v){
    $this->db=$v;
    $this->dropColumn('{{%news}}','name','varchar(20)');
    $this->dropColumn('{{%news}}','nickname','varchar(20)');
    $this->dropColumn('{{%news}}','age','int(3)');
    $this->dropColumn('{{%news}}','sex','int(1)');
    $this->dropColumn('{{%news}}','site_id','int(5)');
  }
}
}

每个数据库迁移都会被定义为一个继承自 yii\db\Migration 的 PHP 类。类的名称按照 m<YYMMDD_HHMMSS>_<Name> 的格式自动生成,其中

<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 是无法恢复的。

访问数据库的方法

迁移的基类 yii\db\Migration 提供了一整套访问和操作数据库的方法。你可能会发现这些方法的命名和 yii\db\Command 类提供的 DAO 方法很类似。 例如,yii\db\Migration::createTable() 方法可以创建一张新的表,这和 yii\db\Command::createTable() 的功能是一模一样的。

使用 yii\db\Migration 所提供的方法的好处在于你不需要再显式的创建 yii\db\Command 实例,而且在执行每个方法的时候都会显示一些有用的信息来告诉我们数据库操作是不是都已经完成,还有它们完成这些操作花了多长时间等等。

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

yii\db\Migration::execute(): 执行一条 SQL 语句
yii\db\Migration::insert(): 插入单行数据
yii\db\Migration::batchInsert(): 插入多行数据
yii\db\Migration::update(): 更新数据
yii\db\Migration::delete(): 删除数据
yii\db\Migration::createTable(): 创建表
yii\db\Migration::renameTable(): 重命名表名
yii\db\Migration::dropTable(): 删除一张表
yii\db\Migration::truncateTable(): 清空表中的所有数据
yii\db\Migration::addColumn(): 加一个字段
yii\db\Migration::renameColumn(): 重命名字段名称
yii\db\Migration::dropColumn(): 删除一个字段
yii\db\Migration::alterColumn(): 修改字段
yii\db\Migration::addPrimaryKey(): 添加一个主键
yii\db\Migration::dropPrimaryKey(): 删除一个主键
yii\db\Migration::addForeignKey(): 添加一个外键
yii\db\Migration::dropForeignKey(): 删除一个外键
yii\db\Migration::createIndex(): 创建一个索引
yii\db\Migration::dropIndex(): 删除一个索引

提交迁移

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

yii migrate

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

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

提示:迁移工具将会自动在数据库当中创建 migration 表,该数据库是在该命令的 yii\console\controllers\MigrateController::db 选项当中指定的。默认情况下,是由 db application component 指定的。

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

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 migrate/redo    # redo the last applied migration 重做最近一次提交的迁移
yii migrate/redo 3   # redo the last 3 applied migrations 重做最近三次提交的迁移

注意:如果一个迁移是不能被还原的,那么你将无法对它进行重做。

列出迁移

你可以使用如下命令列出那些提交了的或者是还未提交的迁移:

yii migrate/history   # 显示最近10次提交的迁移
yii migrate/history 5  # 显示最近5次提交的迁移
yii migrate/history all # 显示所有已经提交过的迁移
yii migrate/new     # 显示前10个还未提交的迁移
yii migrate/new 5    # 显示前5个还未提交的迁移
yii migrate/new all   # 显示所有还未提交的迁移

修改迁移历史

有时候你也许需要简单的标记一下你的数据库已经升级到一个特定的迁移,而不是实际提交或者是还原迁移。这个经常会发生在你手动的改变数据库的一个特定状态,而又不想相应的迁移被重复提交。那么你可以使用如下命令来达到目的:

yii migrate/mark 150101_185401           # 使用时间戳来指定迁移
yii migrate/mark "2015-01-01 18:54:01"       # 使用一个可以被 strtotime() 解析的字符串
yii migrate/mark m150101_185401_create_news_table  # 使用全名
yii migrate/mark 1392853618             # 使用 UNIX 时间戳

该命令将会添加或者删除 migration 表当中的某几行数据来表明数据库已经提交到了指定的某个迁移上。执行这条命令期间不会有任何的迁移会被提交或还原。

自定义迁移

有很多方法可以自定义迁移命令。

使用命令行选项

迁移命令附带了几个命令行选项,可以用来自定义它的行为:

interactive: boolean (默认值为 true),指定是否以交互模式来运行迁移。当被设置为 true 时,在命令执行某些操作前,会提示用户。如果你希望在后台执行该命令,那么你应该把它设置成 false。

migrationPath: string (默认值为 @app/migrations),指定存放所有迁移类文件的目录。该选项可以是一个目录的路径,也可以是 路径别名。需要注意的是指定的目录必选存在,否则将会触发一个错误。

migrationTable: string (默认值为 migration),指定用于存储迁移历史信息的数据库表名称。如果这张表不存在,那么迁移命令将自动创建这张表。当然你也可以使用这样的字段结构: version
 varchar(255) primary key, apply_time integer 来手动创建这张表。

db: string (默认值为 db),指定数据库 application component 的 ID。它指的是将会被该命令迁移的数据库。

templateFile: string (defaults to @yii/views/migration.php),指定生产迁移框架代码类文件的模版文件路径。该选项即可以使用文件路径来指定,也可以使用路径 别名 来指定。该模版文件是一个可以使用预定义变量 $className 来获取迁移类名称的 PHP 脚本。

如下例子向我们展示了如何使用这些选项:

例如,如果我们需要迁移一个 forum 模块,而该迁移文件放在该模块下的 migrations 目录当中,那么我们可以使用如下命令:

# 在 forum 模块中以非交互模式进行迁移
yii migrate --migrationPath=@app/modules/forum/migrations --interactive=0

全局配置命令

在运行迁移命令的时候每次都要重复的输入一些同样的参数会很烦人,这时候,你可以选择在应用程序配置当中进行全局配置,一劳永逸:

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

如上所示配置,在每次运行迁移命令的时候,backend_migration 表将会被用来记录迁移历史。你再也不需要通过 migrationTable 命令行参数来指定这张历史纪录表了。

迁移多个数据库

默认情况下,迁移将会提交到由 db application component 所定义的同一个数据库当中。如果你需要提交到不同的数据库,你可以像下面那样指定 db 命令行选项,

yii migrate --db=db2

上面的命令将会把迁移提交到 db2 数据库当中。

偶尔有限时候你需要提交 一些 迁移到一个数据库,而另外一些则提交到另一个数据库。为了达到这个目的,你应该在实现一个迁移类的时候指定需要用到的数据库组件的 ID , 如下所示:

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

即使你使用 db 命令行选项指定了另外一个不同的数据库,上面的迁移还是会被提交到 db2 当中。需要注意的是这个时候迁移的历史信息依然会被记录到 db 命令行选项所指定的数据库当中。

如果有多个迁移都使用到了同一个数据库,那么建议你创建一个迁移的基类,里面包含上述的 init() 代码。然后每个迁移类都继承这个基类就可以了。

提示:除了在 yii\db\Migration::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 数据库当中,以此类推。

希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。

PHP 相关文章推荐
如何获得PHP相关资料
Oct 09 PHP
Banner程序
Oct 09 PHP
Zend studio for eclipse中使php可以调用mysql相关函数的设置方法
Oct 13 PHP
PHP实现多进程并行操作的详解(可做守护进程)
Jun 18 PHP
PHP仿博客园 个人博客(1) 数据库与界面设计
Jul 05 PHP
C# WinForm中实现快捷键自定义设置实例
Jan 23 PHP
php简单防盗链实现方法
Jul 29 PHP
WordPress中缩略图的使用以及相关技巧
Nov 24 PHP
教你php如何实现验证码
Jan 20 PHP
Thinkphp结合ajaxFileUpload实现异步图片传输示例
Mar 13 PHP
PHP mysqli事务操作常用方法分析
Jul 22 PHP
PHP使用函数用法详解
Sep 30 PHP
yii2高级应用之自定义组件实现全局使用图片上传功能的方法
Oct 08 #PHP
ThinkPHP发送邮件示例代码
Oct 08 #PHP
Yii2针对游客、用户防范规则和限制的解决方法分析
Oct 08 #PHP
Netbeans 8.2与PHP相关的新特性介绍
Oct 08 #PHP
Laravel中基于Artisan View扩展包创建及删除应用视图文件的方法
Oct 08 #PHP
PHP反射API示例分享
Oct 08 #PHP
验证坐标在某坐标区域内php代码
Oct 08 #PHP
You might like
把PHP安装为Apache DSO
2006/10/09 PHP
完整删除ecshop中获取店铺信息的API
2014/12/24 PHP
php简单smarty入门程序实例
2015/06/11 PHP
非集成环境的php运行环境(Apache配置、Mysql)搭建安装图文教程
2016/04/12 PHP
php+ajax+json 详解及实例代码
2016/12/12 PHP
php无限级分类实现评论及回复功能
2019/02/18 PHP
laravel实现于语言包的完美切换方法
2019/09/29 PHP
javascript面向对象编程代码
2011/12/19 Javascript
js鼠标滑过图片震动特效的方法
2015/02/17 Javascript
JQuery.Ajax()的data参数类型实例详解
2015/11/20 Javascript
JS实现环形进度条(从0到100%)效果
2016/07/05 Javascript
Javascript实现代码折叠功能
2016/08/25 Javascript
如何学JavaScript?前辈的经验之谈
2016/12/28 Javascript
微信小程序 引入es6 promise
2017/04/12 Javascript
详解微信小程序input标签正则初体验
2018/08/18 Javascript
koa socket即时通讯的示例代码
2018/09/07 Javascript
jQuery实现动态添加和删除input框实例代码
2019/03/26 jQuery
浅谈Vue SSR中的Bundle的具有使用
2019/11/21 Javascript
vue学习笔记之slot插槽用法实例分析
2020/02/29 Javascript
[00:32]2018DOTA2亚洲邀请赛VG出场
2018/04/03 DOTA
Python返回真假值(True or False)小技巧
2015/04/10 Python
python数据预处理之将类别数据转换为数值的方法
2017/07/05 Python
Python实现动态图解析、合成与倒放
2018/01/18 Python
Python实现求一个集合所有子集的示例
2018/05/04 Python
python 读取二进制 显示图片案例
2020/04/24 Python
使用python编写一个语音朗读闹钟功能的示例代码
2020/07/14 Python
Python OpenCV中的numpy与图像类型转换操作
2020/12/11 Python
CSS3实现多重边框的方法总结
2016/05/31 HTML / CSS
人力资源总监工作说明
2014/03/03 职场文书
镇创先争优活动总结
2014/08/28 职场文书
2014党员学习兰辉先进事迹思想汇报
2014/09/17 职场文书
三人合伙协议书范本
2014/10/29 职场文书
新闻稿格式范文
2015/07/18 职场文书
Python实现的扫码工具居然这么好用!
2021/06/07 Python
基于Redis结合SpringBoot的秒杀案例详解
2021/10/05 Redis
MYSQL事务的隔离级别与MVCC
2022/05/25 MySQL