laravel 基础教程 —— 迁移

数据库:迁移

简介

迁移就像是为数据库提供的版本控制,这允许你的团队可以轻易的修改和共享应用数据库结构。迁移通常配合 laravel 的结构生成器来轻松的构建应用中的数据库结构。

Laravel 的 Schema 假面提供了创建和操作数据库的相关支持。它为所有 Laravel 支持的数据库系统提供了丰富流畅的相同的 API 接口。

生成迁移

你可以使用 make:migration Artisan 命令来生成迁移:

php artisan make:migration create_users_table

新生成的迁移将会被存放在 database/migrations 目录下,每个迁移文件都包含了创建时的时间戳,这样就可以指导 Laravel 按序的进行迁移操作。

你也可以使用 --table--create 选项来指导迁移所创建的表的名称。这些选项只是简单的填充生成的迁移文件为指定的表:

php artisan make:migration add_votes_to_users_table --table=users

php artisan make:migration create_users_table --create=users

如果你想要自定义生成迁移的路径,你可以使用 --path 选项。所提供的路径应该是基于应用根目录的相对路径。

迁移结构

迁移类中包含了两个方法:updownup 方法用来添加新的表,列或者数据库中的索引。而 down 方法应该简单的执行 up 方法的逆操作。

在这个两个方法里你可以使用 Laravel 的结构生成器来进行表的创建和修改。对于所有的 Schema 生成器中可用的方法,请参考 文档。比如,让我们来看一个简单的创建一个 flights 表的迁移:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateFlightsTable extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
   public function up()
   {
     Schema::create('flights', function (Blueprint $table) {
       $table->increments('id');
       $table->string('name');
       $table->string('airline');
       $table->timestamps();
     });
   }

   /**
    * Reverse the migrations.
    *
    * @return void
    */
    public function down()
    {
      Schema::drop('flights');
    }
}

执行迁移

你可以使用 migrate Artisan 命令来执行迁移操作。如果你使用 Homestead virtual machine,你应该在你的虚拟机中运行如下命令:

php artisan migrate

如果你在执行迁移的过程中出现 “class not found” 错误,你可以尝试运行 composer dump-autoload 命令然后重新运行迁移命令。

在生成环境中强制迁移操作

有时候迁移的操作是有害的,这意味着你可能会丢失数据。为了保护你在生产环境中不随意的进行迁移操作,Laravel 会提示你确认执行这些操作。你可以使用 --force 标识来取消这些提示:

php artisan migrate --force

回滚迁移

你可以使用 rollback 命令来将迁移回滚到上一次的迁移操作。你需要注意的是,这个回滚是对最后一次迁移的批量操作的回滚,它可能会包含多个迁移文件:

php artisan migrate:rollback

migrate:reset 命令将回滚所有的迁移操作:

php artisan migrate:reset

在同一个命令里执行回滚 / 迁移操作

migrate:refresh 命令会一次回滚所有的迁移操作,然后接着执行 migrate 命令。该命令可以有效的重新创建你的整个数据库:

php artisan migrate:refresh

php artisan migrate:refresh --seed

编写迁移

创建表

你可以使用 Schema 假面的 create 方法来创建一个新的数据库表。create 方法接收两个参数,第一个参数为表的名称,第二个参数是一个 Closure,该闭包接收一个 Blueprint 对象用来对表进行定义:

Schema::create('users', function (Blueprint $table) {
  $table->increments('id'); 
});

当然,当创建表时,你也可以使用任意的结构生成器的 列方法 来定义表的列。

检查表 / 列是否已经存在

你可以通过使用 hasTablehasColumn 方法来简单的检查所给定的表或者列是否存在:

if (Schema::hasTable('users')) {
  //
}

if (Schema::hasColumn('users', 'email')) {
  //
}

连接 & 存储引擎

如果你想在不是默认的数据库连接中执行 schema 的操作,你可以使用 connection 方法来选择数据库连接:

Schema::connection('foo')->create('users', function ($table) {
  $table->increments('id'); 
});

你也可以在结构生成器中设置 engine 属性来指定表的存储引擎:

Schema::create('users', function ($table) {
  $table->engine = 'InnoDB';

  $table->increments('id'); 
});

重命名 / 删除表

你可以使用 rename 方法来重命名已经存在的表:

Schema::rename($from, $to);

你可以使用 drop 或者 dropifExists 方法来删除存在的表:

Schema::drop('users');

Schema::dropIfExists('users');

重命名含有外键的表

在对表进行重命名之前,你应该先确认表中所有的外键约束在迁移文件中都有一个明确的名称,而不是让 Laravel 分配基于惯例的名称。另外,外键约束名称将引用旧表名。

创建列

你可以使用 Schema 假面的 table 方法来进行已经存在表的更新操作。像 create 方法一样,table 方法接收两个参数:表的名称和一个接收 Blueprint 实例的闭包,我们可以使用 Blueprint 实例来在表中添加列:

Schema::table('users', function ($table) {
  $table->string('email'); 
});

可用的列类型

当然,结构生成器包含了各种的列类型,你可以在构建表时使用它们:

命令 描述
$table->bigIncrements('id'); 使用 "UNSIGNED BIG INTEGER" 类型来设置自增的 ID(主键)
$table->bigInteger('votes'); 使用 BIGINT 类型
$table->binary('data'); 使用 BLOB 类型
$table->boolean('confirmed'); 使用 BOOLEAN 类型
$table->char('name', 4); 使用 CHAR 类型
$table->date('created_at'); 使用 DATE 类型
$table->dateTime('created_at'); 使用 DATETIME 类型
$table->dateTimeTz('created_at'); 使用 DATETIME (和时区) 类型
$table->decimal('amount', 5, 2); 使用 DECIMAL 类型并伴随一个精度和尺度
$table->double('column', 15, 8); 使用 DOUBLE 类型并伴随一个精度,总共 15 个有效数组,并且其中 8 个是小数
$table->enum('choices', ['foo', 'bar']); 使用 ENUM 类型
$table->float('amount'); 使用 FLOAT 类型
$table->increments('id'); 使用 UNSIGNED INTEGER 类型设置自增的 ID(主键)
$table->integer('votes'); 使用 INTEGER 类型
$table->ipAddress('visitor'); 使用 IP 地址类型
$table->json('options'); 使用 JSON 类型
$table->jsonb('options'); 使用 JSONB 类型
$table->longText('description'); 使用 LONGTEXT 类型
$table->macAddress('device'); 使用 MAC 地址类型
$table->mediumInteger('numbers'); 使用 MEDIUMINT 类型
$table->mediumText('description'); 使用 MEDIUMTEXT 类型
$table->morphs('taggable'); 添加一个 INTEGER 类型的 taggable_id 和一个 STRING 类型的 taggable_type
$table->nullableTimestamps(); timestamps() 一样,除了允许 NULLs
$table->rememberToken(); 添加 VARCHAR(100) NULL remember_token
$table->smallInteger('votes'); 使用 SMALLINT 类型
$table->softDeletes(); 为软删除添加 delete_at
$table->string('email'); 使用 VARCHAR 类型
$table->string('name', 100); 使用 VARCHAR 类型并伴随一个长度。
$table->text('description'); 使用 TEXT 类型
$table->time('sunrise'); 使用 TIME 类型
$table->timeTz('sunrise'); 使用 TIME (伴随时区)类型
$table->tinyInteger('numbers'); 使用 TINYINT 类型
$table->timestamp('added_on'); 使用 TIMESTAMP 类型
$table->timestampTz('added_on'); 使用 TIMESTAMP 类型
$table->timestamps(); 添加 created_atupdated_at
$table->uuid('id'); 使用 UUID 类型

修改列

除了上面所列出的列类型,这里也提供了一些其他在添加列的同时增加一些修正的功能。比如,你可以使用 nullable 方法来让列可以为 NULL:

Schema::table('users', function ($table) {
  $table->string('email')->nullable(); 
});

下面列出了一些可用的列的修正方法,这里并没有包含 index modifiers:

变化 描述
->first() 将列放在表的首列(仅支持 MySQL)
->after('column') 将列放置在其他列之后(仅支持 MySQL)
->nullable() 允许列中存在 NULL 值
->default($value) 为列指定默认值
->unsigned() 设置 integer 列为 UNSIGNED
->comment('my comment') 为列添加注释

进行列的修改

先决条件

在进行列的修改之前,你需要先在 composer.json 文件中添加 doctrine/dbal 用来。Doctrine DBAL 类库用来确定列的当前状态,并创建指定列所需调整的 SQL 查询。

更新列的属性

change 方法允许你修改已存在的列的类型,或者修改列的属性。比如,你可能希望增加字符串类型的列的长度。你可以使用 change 方法来让 name 列的长度从 25 到 50:

Schema::table('users', function ($table) {
  $table->string('name', 50)->change(); 
});

我们也想要将列修改为允许 NULL:

Schema::table('users', function ($table) {
  $table->string('name', 50)->nullable()->chage(); 
});

注意: 修改表中含有 enum 类型的列的表中的任意列,目前都没有得到支持。

列的重命名

你可以使用结构生成器的 renameColumn 方法来对列进行重命名,在进行重命名之前,你需要确保 composer.json 文件中引入了 doctrine/dbal 依赖:

Schema::table('users', function ($table) {
  $table->renameColumn('from', 'to'); 
});

注意: 重命名表中含有 enum 类型的列的表,目前都没有得到支持。

删除列

你可以使用结构生成器中的 dropColumn 方法来删除一列:

Schema::table('users', function ($table) {
  $table->dropColumn('votes'); 
});

你也可以传递一个包含了列名称的数组到 dropColumn 方法:

Schema::table('users', function ($table) {
  $table->dropColumn(['votes', 'avatar', 'location']); 
});

注意:如果你删除的是 SQLite 数据库里的列,你需要先在 composer.json 文件里引入 doctrine/dbal 依赖,并且执行 composer update 命令来安装这个类库。
注意: 在使用 SQLite 数据库时,使用单个迁移操作来删除或者修改多个列是行不通的。

建立索引

结构生成器支持多种类型的索引。首先,让我们看一个简单的例子,这个例子指定列的值应该是唯一的。为了创建索引,我们可以简单的在列的定义中链式调用 unique 方法:

$table->string('email')->unique();

另外,你也可以在定义完列之后添加索引:

$table->unique('email');

你也可以通过传递一个列名的数组到 index 方法来创建一个复合的索引:

$table->index(['account_id', 'created_at']);

Laravel 会自动的生成一个合理的索引名称,但是你也可以传递第二个参数来指定索引名称:

$table->index('email', 'my_index_name');

可用的索引类型

命令 描述
$table->primary('id'); 添加主键
$table->primary(['first', 'last']); 添加复合键
$table->unique('email'); 添加唯一的索引
$table->unique('state', 'my_index_name'); 添加自定义的索引名称
$table->index('state'); 添加基础的索引

删除索引

你需要指定一个索引的名称才能删除索引,默认的 Laravel 会自动的分配一个合理的名称到索引。它只是简单的连接表名,索引的列名,索引的类型。这里有一些示例:

命令 描述
$table->dropPrimary('users_id_primary'); 从用户表中删除主键
$table->dropUnique('users_email_unique'); 从用户表中删除唯一的索引
$table->dropIndex('geo_stage_index'); 从 geo 表中删除基础的索引

如果你传递一个列名所组成的数组到删除索引的方法中,常规的索引的名称将根据表名,列名和键的类型来生成:

Schema::table('geo', function ($table) {
  $table->dropIndex(['state']); // Drops index 'geo_state_index' 
});

外键约束

Laravel 也对创建外键约束提供了支持,外键约束用于强制参照表中数据的完整性。比如,让我们在 posts 表中定义一个 user_id 列,并且关联 users 表中的 id 列:

Schema::table('posts', function ($table) {
  $table->integer('user_id')->unsigned();

  $table->foreign('user_id')->references('id')->on('users'); 
});

你也可以指定约束的“关于删除”和“更新”属性所需要的操作:

$table->foreign('user_id')
      ->references('id')->on('users')
      ->onDelete('cascade');

你可以使用 dropForegin 方法来移除外键。外键约束使用了和索引相同的命名方式。所以,我们会串联表名,列名,和 "_foreign" 后缀:

$table->dropForeign('posts_user_id_foreign');

或者你也可以通过传递一个包含列名的数组,它会自动的使用惯例命名来进行外键的移除:

$table->dropForeign(['user_id']);

你也可以在你的迁移中使用下面的方法来开启或者关闭外键约束:

Schema::enableForeignKeyConstraints();

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

推荐阅读更多精彩内容