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 相关文章推荐
用Zend Encode编写开发PHP程序
Oct 09 PHP
一些被忽视的PHP函数(简单整理)
Apr 30 PHP
php下关于Cannot use a scalar value as an array的解决办法
Aug 08 PHP
PHP图片裁剪函数(保持图像不变形)
May 04 PHP
PHP清除数组中所有字符串两端空格的方法
Oct 20 PHP
PHP导入导出Excel代码
Jul 07 PHP
使用PHP similar text计算两个字符串相似度
Nov 06 PHP
php导出生成word的方法
Dec 25 PHP
PHP与Ajax相结合实现登录验证小Demo
Mar 16 PHP
PHP微信开发之根据用户回复关键词\位置返回附近信息
Jun 24 PHP
thinkphp框架无限级栏目的排序功能实现方法示例
Mar 29 PHP
PHP获取类私有属性的3种方法
Sep 10 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
十大“创意”战术!
2020/03/04 星际争霸
一个用php3编写的简单计数器
2006/10/09 PHP
针对初学PHP者的疑难问答(1)
2006/10/09 PHP
深入PHP运行环境配置的详解
2013/06/04 PHP
php将字符串转化成date存入数据库的两种方式
2014/04/28 PHP
PHP 实现的将图片转换为TXT
2015/10/21 PHP
PHP水印类,支持添加图片、文字、填充颜色区域的实现
2017/02/04 PHP
php session的应用详细介绍
2017/03/22 PHP
PHP实现的简单操作SQLite数据库类与用法示例
2017/06/19 PHP
不同浏览器对回车提交表单的处理办法
2010/02/13 Javascript
基于jQuery的一个扩展form序列化到json对象
2010/12/09 Javascript
JSON.stringify 语法实例讲解
2012/03/14 Javascript
ie 7/8不支持trim的属性的解决方案
2014/05/23 Javascript
jquery实现公告翻滚效果
2015/02/27 Javascript
JQuery使用index方法获取Jquery对象数组下标的方法
2015/05/18 Javascript
javascript学习笔记之函数定义
2015/06/25 Javascript
ANGULARJS中使用JQUERY分页控件
2015/09/16 Javascript
JavaScript中运算符规则和隐式类型转换示例详解
2017/09/06 Javascript
Vuex 使用 v-model 配合 state的方法
2018/11/13 Javascript
jquery实现弹窗(系统提示框)效果
2019/12/10 jQuery
JavaScript实现PC端横向轮播图
2020/02/07 Javascript
vuex的使用和简易实现
2021/01/07 Vue.js
[01:05:36]VP vs TNC Supermajor小组赛B组 BO3 第二场 6.2
2018/06/03 DOTA
Python中函数的多种格式和使用实例及小技巧
2015/04/13 Python
用PyQt进行Python图形界面的程序的开发的入门指引
2015/04/14 Python
Python Flask基础教程示例代码
2018/02/07 Python
python高效过滤出文件夹下指定文件名结尾的文件实例
2018/10/21 Python
Python读取Pickle文件信息并计算与当前时间间隔的方法分析
2019/01/30 Python
深入解析python中的实例方法、类方法和静态方法
2019/03/11 Python
基于python traceback实现异常的获取与处理
2019/12/13 Python
Java里面Pass by value和Pass by Reference是什么意思
2016/05/02 面试题
雏鹰争章活动总结
2014/05/09 职场文书
高一学年自我鉴定范文(3篇)
2014/09/26 职场文书
工伤死亡理赔协议书
2014/10/20 职场文书
工作年限证明模板
2014/11/01 职场文书
详解vue中v-for的key唯一性
2021/05/15 Vue.js