Thinkphp 第二章:数据创建和迁移

本章我们来了解下如何进行数据库的创建和迁移,并着重讲解了ThinkPHP5的数据库迁移扩展的使用,学习内容主要包括:

安装扩展

数据迁移是一个扩展包,非核心内置,你需要首先通过composer安装扩展(对composer还不熟悉的朋友可以看云参考官方的快速入门教程中的第一章基础部分的框架composer安装部分):

composer require topthink/think-migration=1.*

指定安装1.*版本是由于最新的2.0版本只适用于5.1版本核心框架。

数据迁移

数据迁移就像是数据库的版本控制,可以确保项目团队轻松修改并保持应用程序的数据库结构的一致性。为了避免手动修改数据库导致的冲突问题,应当尽量避免手动操作数据库,ThinkPHP5.0的数据迁移扩展提供了优雅的方式让你编写迁移脚本和执行迁移。

编写数据迁移脚本是一个良好的习惯和团队协作规范,但并非强制,也不会影响本书后面的章节的学习,如果你感觉暂时用不上可以先略过。

创建迁移脚本

使用下面的命令来创建一个迁移脚本:

php think migrate:create CreateUserTable

如果你对命令行和指令不熟悉,请参考快速入门系列的第一部第十章关于命令行指令的说明。

CreateUserTable 这个脚本名必须为驼峰格式,指令输入完成后,会在项目根目录下的database/migrations目录下创建一个迁移脚本,里面默认有一个change方法。

如果你的迁移脚本里只会有以下的操作:

  • createTable(创建表)
  • renameTable(重命名表)
  • addColumn(添加字段)
  • renameColumn(重命名字段)
  • addIndex(添加索引)
  • addForeignKey(添加外键)

那么你只需要change方法就可以了,回滚的时候可以自动根据change里的操作来逆向操作,否则需要定义updown两个方法,用来表示迁移回滚两个具体的操作。

定义了updown方法后就不要再定义change方法了,在change方法里操作数据表的时候,最后只能使用create()或者update()来完成操作,而不能使用save()

运行迁移

php think migrate:run
// 指定版本
php think migrate:run -t 20120103083322

设置断点

php think migrate:breakpoint

//指定版本
php think migrate:breakpoint -t 20120103083322

回滚迁移

可以回滚上一次数据迁移操作(可能包含多个迁移文件)。

php think migrate:rollback

//指定版本
php think migrate:rollback -t 20120103083322

//回滚所有
php think migrate:rollback -t 0

如果设置了断点,默认最多只可以回滚到断点处,可以使用--force参数强制回滚所有

php think migrate:rollback -t 0 -f

迁移方法

迁移脚本中支持大部分的数据库操作的实现方法,我们陆续给你讲述这些用法。

创建数据表

创建数据表使用create方法,并在之前调用addColumn方法相关方法进行数据字段定义:

public function change()
{
  $this->table('user')
    ->addColumn(Column::string('name')->setComment('用户昵称'))
    ->addColumn(Column::string('username')->setUnique()->setComment('用户名'))
    ->addColumn(Column::string('email')->setUnique()->setComment('邮箱'))
    ->addColumn(Column::string('password')->setComment('密码'))
    ->create();
}

addColumn方法添加字段传入一个Column对象实例,后面会详细介绍该对象的使用。

或者使用updown

public function up()
{
  $this->table('user')
    ->addColumn(Column::string('name')->setComment('用户昵称'))
    ->addColumn(Column::string('username')->setUnique()->setComment('用户名'))
    ->addColumn(Column::string('email')->setUnique()->setComment('邮箱'))
    ->addColumn(Column::string('password')->setComment('密码'))
    ->create();
}

/**
* Down Method.
*/
public function down()
{
    $this->dropTable('user');
}

检查数据表或字段是否存在

if($this->hasTable('user')){
    //
}
if($this->table('user')->hasColumn('username')){
    //
}

存储引擎

$this->table('user',['engine'=>'MyISAM'])

默认为 InnoDB

设置主键

默认会自动添加一个id自增主键

$this->table('followers')
    ->setId(false) //关闭自动设置主键
    ->setPrimaryKey(['user_id','follower_id']) //设置联合主键
     ->addColumn(Column::integer('user_id'))
    ->addColumn(Column::integer('follower_id'))
    ->create();

默认的主键是自增的,如果不需要自增可以如下

$this->table('followers')
    ->setId('user_id') 
    ->addColumn(Column::integer('follower_id'))
    ->create();

重命名与删除数据表

//重命名
$this->table('user')->rename('user2');

//删除
$this->table('user')->drop();
//或者
$this->dropTable('user');

可用字段

数据库结构构造器包含了许多字段类型,供你构建数据表时使用:

命令 描述
Column::bigInteger('votes'); 相当于 BIGINT 型态。
Column::binary('data'); 相当于 BLOB 型态。
Column::boolean('confirmed'); 相当于 BOOLEAN 型态。
Column::char('name', 4); 相当于 CHAR 型态,并带有长度。
Column::date('create_time'); 相当于 DATE 型态。
Column::dateTime('create_time'); 相当于 DATETIME 型态。
Column::decimal('amount', 5, 2); 相当于 DECIMAL 型态,并带有精度与基数。
Column::enum('choices', ['foo', 'bar']); 相当于 ENUM 型态。
Column::float('amount'); 相当于 FLOAT 型态。
Column::integer('votes'); 相当于 INTEGER 型态。
Column::json('options'); 相当于 JSON 型态。
Column::jsonb('options'); 相当于 JSONB 型态。
Column::longText('description'); 相当于 LONGTEXT 型态。
Column::mediumInteger('numbers'); 相当于 MEDIUMINT 型态。
Column::mediumText('description'); 相当于 MEDIUMTEXT 型态。
Column::smallInteger('votes'); 相当于 SMALLINT 型态。
Column::string('email'); 相当于 VARCHAR 型态。
Column::string('name', 100); 相当于 VARCHAR 型态,并带有长度。
Column::text('description'); 相当于 TEXT 型态。
Column::time('sunrise'); 相当于 TIME 型态。
Column::tinyInteger('numbers'); 相当于 TINYINT 型态。
Column::timestamp('added_on'); 相当于 TIMESTAMP 型态。
Column::uuid('id'); 相当于 UUID 型态。

字段修饰

除了上述的字段类型列表,还有一些其它的字段「修饰」,你可以将它增加到字段中。例如,若要让字段「nullable」,那么你可以使用 setNullable 方法:

  $this->table('user')
    ->addColumn(Column::string('name')->setNullable())
    ->create();

以下列表为字段的可用修饰。

修饰 描述
->setAfter('column') 将此字段放置在其它字段「之后」(仅限 MySQL)
->setComment('my comment') 增加注释
->setDefault($value) 为此字段指定「默认」值
->setNullable() 此字段允许写入 NULL 值
->setUnsigned() 设置 integer 字段为 UNSIGNED

特殊字段

$this->table('user')
  ->addTimestamps() //添加create_time和update_time两个字段
  ->addSoftDelete()  //添加delete_time字段
  ->addMorphs('taggable')  //加入整数 taggable_id 与字符串 taggable_type
  ->create();

修改字段

//重命名字段
 $this->table('user')->renameColumn('old_name','new_name');

 //修改字段属性
  $this->table('user')->changeColumn(Column::integer('votes')->setNullable());

移除字段

$this->table('user')->removeColumn('name');

创建索引

数据库结构构造器支持多种类型的索引。首先,让我们先来看一个示例,其指定了字段的值必须是唯一的。你可以简单的在字段定义之后链式调用 setUnique 方法来创建索引:

  $this->table('user')
    ->addColumn(Column::string('name')->setUnique()->setNullable())
    ->create();

此外,你也可以在定义完字段之后创建索引。例如:

  $this->table('user')
    ->addColumn(Column::string('name')->setNullable())
    ->addIndex('name',['unique'=>true])
    ->create();

你也可以传递一个字段的数组至索引方法来创建复合索引:

addIndex(['name','email'])

移除索引

 $this->table('user')->removeIndex('name');

  $this->table('user')->removeIndex(['name','email']);

外键约束

        $table = $this->table('tags');
        $table->addColumn(Column::integer('tag_name'))
              ->save();

 $this->table('tag_relationships')
 ->addColumn(Column::integer('tag_id'))
 ->addForeignKey('tag_id', 'tags', 'id', array('delete'=> 'SET_NULL', 'update'=> 'NO_ACTION'))
 ->save();

总结

现在我们已经大概了解了数据迁移扩展的使用,没有搞懂的话暂时无需深究,真正有机会的时候再来深入,我们下一章就要开始学习查询构造器的使用了。

上一篇:第一章:数据库架构基础
下一篇:第三章:查询构造器

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349