数据库:迁移 
介绍 
迁移就像是数据库的版本控制,允许你的团队轻松修改和共享应用程序的数据库架构。迁移通常与 Laravel 的架构构建器配对使用,以便轻松构建应用程序的数据库架构。如果你曾经需要告诉队友手动向他们的本地数据库架构添加一列,那么你就遇到了数据库迁移所解决的问题。
Laravel 的 Schema facade 提供了数据库无关的支持,用于在所有 Laravel 支持的数据库系统中创建和操作表。
生成迁移 
要创建迁移,请使用 make:migration Artisan 命令:
php artisan make:migration create_users_table新的迁移将被放置在你的 database/migrations 目录中。每个迁移文件名都包含一个时间戳,这使得 Laravel 能够确定迁移的顺序。
--table 和 --create 选项也可以用来指示表的名称以及迁移是否将创建一个新表。这些选项只是预填充生成的迁移模板文件中的指定表:
php artisan make:migration create_users_table --create=users
php artisan make:migration add_votes_to_users_table --table=users如果你想为生成的迁移指定一个自定义输出路径,可以在执行 make:migration 命令时使用 --path 选项。给定的路径应该是相对于应用程序的基路径。
迁移结构 
迁移类包含两个方法:up 和 down。up 方法用于向数据库添加新表、列或索引,而 down 方法应该简单地反转 up 方法执行的操作。
在这两个方法中,你可以使用 Laravel 架构构建器来表达性地创建和修改表。要了解架构构建器上所有可用的方法,请查看其文档。例如,这个迁移示例创建了一个 flights 表:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateFlightsTable extends Migration
{
    /**
     * 运行迁移。
     *
     * @return void
     */
    public function up()
    {
        Schema::create('flights', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('airline');
            $table->timestamps();
        });
    }
    /**
     * 反转迁移。
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('flights');
    }
}运行迁移 
要运行所有未完成的迁移,请执行 migrate Artisan 命令:
php artisan migrateNOTE
如果你正在使用 Homestead 虚拟机,你应该在虚拟机内运行此命令。
强制在生产环境中运行迁移 
某些迁移操作是破坏性的,这意味着它们可能导致数据丢失。为了保护你不在生产数据库上运行这些命令,在命令执行之前会提示你确认。要强制命令在没有提示的情况下运行,请使用 --force 标志:
php artisan migrate --force回滚迁移 
要回滚最新的迁移操作,可以使用 rollback 命令。此命令回滚最后一个“批次”的迁移,其中可能包含多个迁移文件:
php artisan migrate:rollback你可以通过为 rollback 命令提供 step 选项来回滚有限数量的迁移。例如,以下命令将回滚最后五个迁移:
php artisan migrate:rollback --step=5migrate:reset 命令将回滚应用程序的所有迁移:
php artisan migrate:reset在单个命令中回滚和迁移 
migrate:refresh 命令将回滚所有迁移,然后执行 migrate 命令。此命令有效地重新创建整个数据库:
php artisan migrate:refresh
// 刷新数据库并运行所有数据库种子...
php artisan migrate:refresh --seed你可以通过为 refresh 命令提供 step 选项来回滚和重新迁移有限数量的迁移。例如,以下命令将回滚和重新迁移最后五个迁移:
php artisan migrate:refresh --step=5表 
创建表 
要创建一个新的数据库表,请在 Schema facade 上使用 create 方法。create 方法接受两个参数。第一个是表的名称,第二个是一个 Closure,它接收一个 Blueprint 对象,可以用来定义新表:
Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
});当然,在创建表时,你可以使用架构构建器的任何列方法来定义表的列。
检查表/列是否存在 
你可以使用 hasTable 和 hasColumn 方法轻松检查表或列是否存在:
if (Schema::hasTable('users')) {
    //
}
if (Schema::hasColumn('users', 'email')) {
    //
}连接和存储引擎 
如果你想在非默认连接的数据库上执行架构操作,请使用 connection 方法:
Schema::connection('foo')->create('users', function (Blueprint $table) {
    $table->increments('id');
});你可以在架构构建器上使用 engine 属性来定义表的存储引擎:
Schema::create('users', function (Blueprint $table) {
    $table->engine = 'InnoDB';
    $table->increments('id');
});重命名/删除表 
要重命名现有的数据库表,请使用 rename 方法:
Schema::rename($from, $to);要删除现有表,可以使用 drop 或 dropIfExists 方法:
Schema::drop('users');
Schema::dropIfExists('users');重命名带有外键的表 
在重命名表之前,你应该验证表上的任何外键约束在你的迁移文件中有一个显式名称,而不是让 Laravel 分配一个基于约定的名称。否则,外键约束名称将引用旧的表名。
列 
创建列 
Schema facade 上的 table 方法可用于更新现有表。与 create 方法一样,table 方法接受两个参数:表的名称和一个 Closure,它接收一个 Blueprint 实例,你可以用来向表中添加列:
Schema::table('users', function (Blueprint $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', 8, 2); | 数据库的 FLOAT 等效,总共 8 位数字,小数点后 2 位。 | 
| $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->mediumIncrements('id'); | 使用“UNSIGNED MEDIUM INTEGER”等效的递增 ID(主键)。 | 
| $table->mediumInteger('numbers'); | 数据库的 MEDIUMINT 等效。 | 
| $table->mediumText('description'); | 数据库的 MEDIUMTEXT 等效。 | 
| $table->morphs('taggable'); | 添加无符号 INTEGER taggable_id和 STRINGtaggable_type。 | 
| $table->nullableMorphs('taggable'); | morphs()列的可空版本。 | 
| $table->nullableTimestamps(); | timestamps()列的可空版本。 | 
| $table->rememberToken(); | 添加 remember_token作为 VARCHAR(100) NULL。 | 
| $table->smallIncrements('id'); | 使用“UNSIGNED SMALL INTEGER”等效的递增 ID(主键)。 | 
| $table->smallInteger('votes'); | 数据库的 SMALLINT 等效。 | 
| $table->softDeletes(); | 为软删除添加可空的 deleted_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_at和updated_at列。 | 
| $table->timestampsTz(); | 添加可空的 created_at和updated_at(带时区)列。 | 
| $table->unsignedBigInteger('votes'); | 数据库的无符号 BIGINT 等效。 | 
| $table->unsignedInteger('votes'); | 数据库的无符号 INT 等效。 | 
| $table->unsignedMediumInteger('votes'); | 数据库的无符号 MEDIUMINT 等效。 | 
| $table->unsignedSmallInteger('votes'); | 数据库的无符号 SMALLINT 等效。 | 
| $table->unsignedTinyInteger('votes'); | 数据库的无符号 TINYINT 等效。 | 
| $table->uuid('id'); | 数据库的 UUID 等效。 | 
列修饰符 
除了上面列出的列类型外,还有几个列“修饰符”可以在向数据库表添加列时使用。例如,要使列“可空”,可以使用 nullable 方法:
Schema::table('users', function (Blueprint $table) {
    $table->string('email')->nullable();
});以下是所有可用列修饰符的列表。此列表不包括索引修饰符:
| 修饰符 | 描述 | 
|---|---|
| ->after('column') | 将列放在另一个列“之后”(仅限 MySQL) | 
| ->comment('my comment') | 向列添加注释 | 
| ->default($value) | 为列指定“默认”值 | 
| ->first() | 将列放在表的“首位”(仅限 MySQL) | 
| ->nullable() | 允许向列中插入 NULL 值 | 
| ->storedAs($expression) | 创建存储生成的列(仅限 MySQL) | 
| ->unsigned() | 将 integer列设置为UNSIGNED | 
| ->virtualAs($expression) | 创建虚拟生成的列(仅限 MySQL) | 
修改列 
先决条件 
在修改列之前,请确保在 composer.json 文件中添加 doctrine/dbal 依赖项。Doctrine DBAL 库用于确定列的当前状态并创建所需的 SQL 查询以对列进行指定的调整:
composer require doctrine/dbal更新列属性 
change 方法允许你将某些现有列类型修改为新类型或修改列的属性。例如,你可能希望增加字符串列的大小。要查看 change 方法的实际应用,让我们将 name 列的大小从 25 增加到 50:
Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->change();
});我们还可以将列修改为可空:
Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->nullable()->change();
});NOTE
以下列类型不能“更改”:char, double, enum, mediumInteger, timestamp, tinyInteger, ipAddress, json, jsonb, macAddress, mediumIncrements, morphs, nullableMorphs, nullableTimestamps, softDeletes, timeTz, timestampTz, timestamps, timestampsTz, unsignedMediumInteger, unsignedTinyInteger, uuid。
重命名列 
要重命名列,可以在架构构建器上使用 renameColumn 方法。在重命名列之前,请确保在 composer.json 文件中添加 doctrine/dbal 依赖项:
Schema::table('users', function (Blueprint $table) {
    $table->renameColumn('from', 'to');
});NOTE
在同时具有 enum 类型列的表中重命名任何列目前不受支持。
删除列 
要删除列,请在架构构建器上使用 dropColumn 方法。在从 SQLite 数据库中删除列之前,你需要在 composer.json 文件中添加 doctrine/dbal 依赖项,并在终端中运行 composer update 命令以安装库:
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('votes');
});你可以通过将列名数组传递给 dropColumn 方法来从表中删除多个列:
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn(['votes', 'avatar', 'location']);
});NOTE
在使用 SQLite 数据库时,在单个迁移中删除或修改多个列不受支持。
索引 
创建索引 
架构构建器支持多种类型的索引。首先,让我们看一个指定列的值应该是唯一的示例。要创建索引,我们可以简单地将 unique 方法链接到列定义上:
$table->string('email')->unique();或者,你可以在定义列之后创建索引。例如:
$table->unique('email');你甚至可以将列数组传递给索引方法以创建复合索引:
$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->unique(['first', 'last']); | 添加复合唯一索引。 | 
| $table->index('state'); | 添加基本索引。 | 
索引长度与 MySQL / MariaDB 
Laravel 默认使用 utf8mb4 字符集,其中包括在数据库中存储“表情符号”的支持。如果你运行的 MySQL 版本低于 5.7.7 或 MariaDB 版本低于 10.2.2,你可能需要手动配置迁移生成的默认字符串长度,以便 MySQL 为它们创建索引。你可以通过在 AppServiceProvider 中调用 Schema::defaultStringLength 方法来配置此项:
use Illuminate\Support\Facades\Schema;
/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}或者,你可以为数据库启用 innodb_large_prefix 选项。请参阅数据库的文档以了解如何正确启用此选项。
删除索引 
要删除索引,你必须指定索引的名称。默认情况下,Laravel 会自动为索引分配一个合理的名称。只需连接表名、索引列名和索引类型即可。以下是一些示例:
| 命令 | 描述 | 
|---|---|
| $table->dropPrimary('users_id_primary'); | 从“users”表中删除主键。 | 
| $table->dropUnique('users_email_unique'); | 从“users”表中删除唯一索引。 | 
| $table->dropIndex('geo_state_index'); | 从“geo”表中删除基本索引。 | 
如果你将列数组传递给删除索引的方法,则基于表名、列和键类型的常规索引名称将被生成:
Schema::table('geo', function (Blueprint $table) {
    $table->dropIndex(['state']); // 删除索引 'geo_state_index'
});外键约束 
Laravel 还提供了创建外键约束的支持,这些约束用于在数据库级别强制执行参照完整性。例如,让我们在 posts 表上定义一个 user_id 列,该列引用 users 表上的 id 列:
Schema::table('posts', function (Blueprint $table) {
    $table->integer('user_id')->unsigned();
    $table->foreign('user_id')->references('id')->on('users');
});你还可以为约束的“on delete”和“on update”属性指定所需的操作:
$table->foreign('user_id')
      ->references('id')->on('users')
      ->onDelete('cascade');要删除外键,可以使用 dropForeign 方法。外键约束使用与索引相同的命名约定。因此,我们将连接表名和约束中的列,然后在名称后加上“_foreign”:
$table->dropForeign('posts_user_id_foreign');或者,你可以传递一个数组值,当删除时将自动使用常规约束名称:
$table->dropForeign(['user_id']);你可以在迁移中使用以下方法启用或禁用外键约束:
Schema::enableForeignKeyConstraints();
Schema::disableForeignKeyConstraints();