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 相关文章推荐
如何分别全角和半角以避免乱码
Oct 09 PHP
PHP中PDO基础教程 入门级
Sep 04 PHP
php数组函数序列之array_combine() - 数组合并函数使用说明
Oct 29 PHP
PHP图片处理类 phpThumb参数用法介绍
Mar 11 PHP
php中HTTP_REFERER函数用法实例
Nov 21 PHP
php递归删除目录与文件的方法
Jan 30 PHP
ThinkPHP连接Oracle数据库
Apr 22 PHP
php类自动装载、链式操作、魔术方法实现代码
Jul 23 PHP
PHP实现超简单的SSL加密解密、验证及签名的方法示例
Aug 28 PHP
PHP中cookie知识点学习
May 06 PHP
PHP实现文字写入图片功能
Feb 18 PHP
YII2框架中使用RBAC对模块,控制器,方法的权限控制及规则的使用示例
Mar 18 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
thinkPHP实现的省市区三级联动功能示例
2017/05/05 PHP
PHP 进程池与轮询调度算法实现多任务的示例代码
2019/11/26 PHP
JavaScript NaN和Infinity特殊值 [译]
2012/09/20 Javascript
jquery easyui滚动条部分设置介绍
2013/09/12 Javascript
javascript:FF/Chrome与IE动态加载元素的区别说明
2014/01/26 Javascript
js中创建对象的几种方式示例介绍
2014/01/26 Javascript
Js实现简单的小球运动特效
2016/02/18 Javascript
两种js监听滚轮事件的实现方法
2016/05/13 Javascript
js+html5实现canvas绘制椭圆形图案的方法
2016/05/21 Javascript
jQuery EasyUI提交表单验证
2016/07/19 Javascript
vue.js开发环境安装教程
2017/03/17 Javascript
利用js编写网页进度条效果
2017/10/08 Javascript
JS数组去重常用方法实例小结【4种方法】
2018/05/28 Javascript
对angularJs中ng-style动态改变样式的实例讲解
2018/09/30 Javascript
如何在vue中使用jointjs过程解析
2020/05/29 Javascript
解决iview table组件里的 固定列 表格不自适应的问题
2020/11/13 Javascript
[13:16]INFAMOUS vs VGJ T BO3
2018/06/07 DOTA
[43:32]Winstrike vs VGJ.S 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
Python实现的读写json文件功能示例
2018/06/05 Python
django开发post接口简单案例,获取参数值的方法
2018/12/11 Python
对Python多线程读写文件加锁的实例详解
2019/01/14 Python
解决Atom安装Hydrogen无法运行python3的问题
2019/08/28 Python
Python3 sys.argv[ ]用法详解
2019/10/24 Python
python3实现弹弹球小游戏
2019/11/25 Python
Pytorch 神经网络—自定义数据集上实现教程
2020/01/07 Python
使用tensorflow显示pb模型的所有网络结点方式
2020/01/23 Python
关于tf.TFRecordReader()函数的用法解析
2020/02/17 Python
DNA测试:Orig3n
2019/03/01 全球购物
JPA的优势都有哪些
2013/07/04 面试题
纪委书记群众路线整改措施思想汇报
2014/10/09 职场文书
2015年药店店长工作总结
2015/04/29 职场文书
公务员保密工作承诺书
2015/05/04 职场文书
《平移和旋转》教学反思
2016/02/19 职场文书
Python数据可视化之用Matplotlib绘制常用图形
2021/06/03 Python
PostGIS的安装与入门使用指南
2022/01/18 PostgreSQL
vmware虚拟机打不开vmx文件怎么办 ?vmware虚拟机vmx文件打开方法
2022/04/08 数码科技