什么是Migration?
migration用谷歌翻译是移民的意思,在PHP中我们将它理解为迁移,将Migration用在数据库上就理解为数据库迁移咯。在migration开发之前,我们都是手写SQL创建表语句,创建成功之后需要手动在数据库执行,项目初始化光数据库的创建就花费很多时间。
另外在多人团队开发中,如果要求每个开发人员都在本地使用数据库那么我们通常都是将数据库备份成SQL文件互相传递,这还并不是很繁琐,繁琐的在于如果数据库某个表的字段出现变动那么就需要将这个变动的SQL语句传给每个开发小伙伴让他们在本地都手动的更新下,一次可以这样,但是多次呢?我想在开发团队中这种事情肯定让人头疼咯,所以migration就诞生咯。
Migration就是一些管理数据库结构的文件,这些文件其实都是抽象化的SQL,可以通过命令行执行而改变数据库的结构,这些文件都是存放在项目下的,随着项目版本的迭代而迭代。
在开发过程中,如果一位小伙伴改动了数据库的表结构,她只需要生成一个migration文件并推送到版本控制系统中,如:Git,并通知其他小伙伴,其他小伙伴只需要pull然后在命令行执行下migration命令就可以了,简化了传统的数据库变动流程,加快项目的开发。
Migration文件作用
migration 文件的主要作用就是用来管理数据库的结构,其实它是一组SQL语句的抽象化,migration 文件可以创建表,删除表,增加字段,删除字段等等基本上所有的数据库操作,其实这就像你自己手动写SQL语句一样,只不过在 migration 中你不需要手动的写SQL语句,只需要按照它的规则语法调用一下就可以啦。
migrate 命令介绍
migrate:breakpoint
管理断点migrate:create
创建一个迁移文件migrate:rollback
回滚最后一个或特定的迁移migrate:run
迁移数据库migrate:status
显示迁移状态
Thinkphp5.1 使用 migration
thinkphp5 为开发者提供了一整套的 migration 解决方案,不过默认情况下 migration 是没有安装的,需要我们手动安装。将工作目录切换到tp5项目下,执行:
代码语言:javascript复制composer require topthink/think-migration v2.0.3
默认安装的TP6版本,这里指定安装tp5.1 的版本为V2.0.3,更多版本地址:https://packagist.org/packages/topthink/think-migration
执行php think
命令查看是否安装成功
从图中我们可以看到 migration 和 seed ,表示安装成功了
create 命令
语法格式:php think migrate:create TableName
TableName
格式:首字母大写的驼峰法。该命令是用来创建一个 migration 文件,比如这里我们创建一个 Video
的 migration 文件:
php think migrate:create Video
第一次执行 Migraton 它会提示一些信息,这里全部统一 yes 就可以啦。创建成功如下:
代码语言:javascript复制# php think migrate:create Video
PHP Warning: Module 'redis' already loaded in Unknown on line 0
Create migrations directory? [y]/n (yes/no) [yes]:
> yes
created ./database/migrations/20190804032741_video.php
在项目的根目录下多了一个 database 目录,有一个migration文件夹,该文件夹就是用来存放 migration文件,打开可以看到我们刚才创建的 Video 的 migration 文件:
文件格式命名规则:
时间 随机数 _ 文件名
文件创建好之后,来看下它的内容:
代码语言:javascript复制<?php
use thinkmigrationMigrator;
use thinkmigrationdbColumn;
class Video extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
}
}
这里我需要给我上面创建的 Video 文件增加字段
Video 表结构如下
字段 | 类型 | 说明 |
---|---|---|
id | int | 主键 |
nickname | varchar(16) | 视频名称 |
varchar(32) | 邮箱 | |
password | varchar64) | 密码 |
删除默认自带的
change
方法,创建up()
方法和down()
方法。up()
方法是在执行run
命令执行的,down()
是在执行rollback
命令执行的。
up()
方法如下 :
public function up()
{
$table = $this->table('video');
$table->addColumn('name', 'string', ['limit' => 16, 'null' => false,'comment'=>'视频名称'])
->addColumn('email', 'string', ['limit' => 32, 'null' => false,'comment'=>'邮箱'])
->addColumn('password', 'string', ['limit' => 64, 'null' => false,'comment'=>'密码'])
->create();
}
down()
方法如下:
public function down()
{
$this->dropTable('video');
}
文件整体内容
代码语言:javascript复制<?php
use thinkmigrationMigrator;
use thinkmigrationdbColumn;
class Video extends Migrator
{
public function up()
{
$table = $this->table('video');
$table->addColumn('name', 'string', ['limit' => 16, 'null' => false,'comment'=>'名称'])
->addColumn('email', 'string', ['limit' => 32, 'null' => false,'comment'=>'邮箱'])
->addColumn('password', 'string', ['limit' => 64, 'null' => false,'comment'=>'密码'])
->create();
}
public function down()
{
$this->dropTable('video');
}
}
这样,一个可以创建 video 表的 migration 文件就创建完毕了,接下来,来学习下一个命令。
run 命令
migration 文件创建完毕,还需要执行 run
命令才可以修改数据库:
代码语言:javascript复制注意,执行此步骤之前请正确配置了
config/database.php
。在这里的数据库是有前缀的iot_
。
php think migrate:run
执行成功之后,查看数据库,多了两个表iot_migrations
和iot_video
iot_video
表结构如下
mysql> desc iot_video;
---------- ------------- ------ ----- --------- ----------------
| Field | Type | Null | Key | Default | Extra |
---------- ------------- ------ ----- --------- ----------------
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(16) | NO | | NULL | |
| email | varchar(32) | NO | | NULL | |
| password | varchar(64) | NO | | NULL | |
---------- ------------- ------ ----- --------- ----------------
4 rows in set (0.07 sec)
之前我定义了 migration 只指定了
nickname
,password
三个字段,但是执行run
命令创建的表中有四个字段,多了一个id
主键?这是thinkphp5
为我们默认添加的!小伙伴注意啦!如果你的主键字段名为id
就不需要自己手动的指定了。
iot_video
设计表结构查看注释
iot_migrations
表中的内容是什么?
mysql> select * from iot_migrations G;
---------------- ---------------- --------------------- --------------------- ------------
| version | migration_name | start_time | end_time | breakpoint |
---------------- ---------------- --------------------- --------------------- ------------
| 20190804032741 | Video | 2019-08-04 11:49:49 | 2019-08-04 11:49:50 | 0 |
---------------- ---------------- --------------------- --------------------- ------------
1 row in set (0.08 sec)
可以看出是刚才执行run命名成功后的一条记录,版本20190804032741是和文件名一一对应的
status 命令
代码语言:javascript复制# php think migrate:status
Status Migration ID Started Finished Migration Name
----------------------------------------------------------------------------------
up 20190804032741 2019-08-04 11:49:49 2019-08-04 11:49:50 Video
列表的形式展示了 migration 的执行情况
breakpoint 命令
RedisSubscribe 类
代码语言:javascript复制class RedisSubscribe
{
public function subscribe()
{
$redis = BaseRedis::plocal();
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
// 这里是键空间过期是选用的1号数据库
$redis->psubscribe(array('__keyevent@1__:expired'), function ($redis, $pattern, $chan, $msg) {
Log::info('[订阅事件] 过期KEY ' . $msg);
$originData = explode(':', $msg);
$event_key = $originData[1] ?? '0';
$event_status = $originData[0] ?? '0';
// 根据事件类型做出业务处理既可
});
}
}
$msg 变量就是一个Redis的键key,如,订单过期时间(订单多长时间后延迟取消),可以设置键:
S20190722100001:1001
1、S20190722100001
表示订单号 2、1001
表示是具体是哪个订单事件。 3、如:1001表示订单过期(二维码过期不能够进行支付,失效二维码),1002表示多长时间之内(30分钟之内之未支付取消)未支付需要取消的订单事件。