Skip to content

数据库迁移

介绍

迁移就像数据库的版本控制,允许您的团队定义和共享应用程序的数据库架构定义。如果您曾经不得不告诉团队成员在从源代码控制中提取更改后手动将列添加到他们的本地数据库架构中,那么您就遇到了数据库迁移可以解决的问题。

Laravel Schemafacade为跨 Laravel 支持的所有数据库系统创建和操作表提供了与数据库无关的支持。通常,迁移将使用此 Facade 来创建和修改数据库表和列。

生成迁移

您可以使用 make:migrationArtisan 命令生成数据库迁移。新的迁移将放置在 database/migrations 目录中。每个迁移文件名都包含一个时间戳,允许 Laravel 确定迁移的顺序:

shell
php artisan make:migration create_flights_table

Laravel 将使用迁移的名称来尝试猜测表的名称以及迁移是否会创建一个新表。如果 Laravel 能够从迁移名称中确定表名,Laravel 将使用指定的表预先填充生成的迁移文件。否则,您只需在迁移文件中手动指定表即可。

如果您想为生成的迁移指定自定义路径,您可以在执行 make:migration 命令时使用 --path 选项。给定的路径应相对于应用程序的基路径。

NOTE

可以使用 stub publishing 自定义迁移.

压缩迁移

在构建应用程序时,随着时间的推移,您可能会累积越来越多的迁移。这可能会导致您的 database/migrations 目录变得臃肿,可能会有数百个迁移。如果您愿意,可以将迁移 “压缩” 到单个 SQL 文件中。要开始使用,请执行 schema:dump 命令:

shell
php artisan schema:dump

# 转储当前数据库架构并删除所有现有的迁移...
php artisan schema:dump --prune

当您执行此命令时,Laravel 会将 “schema” 文件写入应用程序的 database/schema 目录。架构文件的名称将与数据库连接相对应。现在,当您尝试迁移数据库并且没有执行其他迁移时,Laravel 将首先执行您正在使用的数据库连接的架构文件中的 SQL 语句。执行架构文件的 SQL 语句后,Laravel 将执行不属于架构转储的任何剩余迁移。

如果您的应用程序的测试使用的数据库连接与您在本地开发期间通常使用的数据库连接不同,则应确保已使用该数据库连接转储架构文件,以便您的测试能够构建数据库。您可能希望在转储本地开发期间通常使用的数据库连接后执行此操作:

shell
php artisan schema:dump
php artisan schema:dump --database=testing --prune

您应该将数据库架构文件提交到源代码管理,以便您团队中的其他新开发人员可以快速创建应用程序的初始数据库结构。

WARNING

迁移压缩仅适用于 MariaDB、MySQL、PostgreSQL 和 SQLite 数据库,并利用数据库的命令行客户端。

迁移结构

迁移类包含两个方法:updownup 方法用于向数据库添加新的表、列或索引,而 down 方法应反转 up 方法执行的操作。

在这两种方法中,您都可以使用 Laravel 架构构建器来富有表现力地创建和修改表。要了解 Schema 构建器上提供的所有方法,请查看其文档。例如,以下迁移会创建一个 flights 表:

php
    <?php

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

    return new class extends Migration
    {
        /**
         * 运行迁移
         */
        public function up(): void
        {
            Schema::create('flights', function (Blueprint $table) {
                $table->id();
                $table->string('name');
                $table->string('airline');
                $table->timestamps();
            });
        }

        /**
         * 反转迁移
         */
        public function down(): void
        {
            Schema::drop('flights');
        }
    };

设置迁移连接

如果您的迁移将与应用程序的默认数据库连接以外的数据库连接进行交互,则应设置迁移的 $connection 属性:

php
    /**
     * 迁移应使用的数据库连接
     *
     * @var string
     */
    protected $connection = 'pgsql';

    /**
     * 运行迁移
     */
    public function up(): void
    {
        // ...
    }

运行迁移

要运行所有未完成的迁移,请执行 migrate Artisan 命令:

shell
php artisan migrate

如果您想查看到目前为止已经运行了哪些迁移,您可以使用 migrate:status Artisan 命令:

shell
php artisan migrate:status

如果您想查看迁移将执行的 SQL 语句,而不实际运行它们,则可以为 migrate 命令提供 --pretend 标志:

shell
php artisan migrate --pretend

隔离迁移执行

如果要跨多个服务器部署应用程序,并在部署过程中运行迁移,则可能不希望两台服务器同时尝试迁移数据库。为避免这种情况,您可以在调用 migrate 命令时使用 isolated 选项。

当提供 isolated 选项时,Laravel 将在尝试运行迁移之前使用应用程序的缓存驱动程序获取原子锁。在持有该锁时运行 migrate 命令的所有其他尝试都不会执行;但是,该命令仍将退出并显示 Success exit status code:

shell
php artisan migrate --isolated

WARNING

要使用此功能,您的应用程序必须使用 memcachedredisdynamodb数据库文件数组缓存驱动程序作为应用程序的默认缓存驱动程序。此外,所有服务器都必须与同一个中央缓存服务器通信。

强制迁移在生产环境中运行

某些迁移操作具有破坏性,这意味着它们可能会导致您丢失数据。为了防止您对生产数据库运行这些命令,在执行这些命令之前,系统将提示您进行确认。要强制命令在没有提示符的情况下运行,请使用 --force 标志:

shell
php artisan migrate --force

回滚迁移

要回滚最新的迁移操作,您可以使用 rollback Artisan 命令。此命令将回滚最后“一批”迁移,其中可能包括多个迁移文件:

shell
php artisan migrate:rollback

您可以通过为 rollback 命令提供 step 选项来回滚有限数量的迁移。例如,以下命令将回滚最后 5 次迁移:

shell
php artisan migrate:rollback --step=5

您可以通过向 rollback 命令提供 batch 选项来回滚特定的“batch”迁移,其中 batch 选项对应于应用程序的 migrations 数据库表中的 batch 值。例如,以下命令将回滚第三批中的所有迁移:

shell
php artisan migrate:rollback --batch=3

如果您想查看迁移将执行的 SQL 语句,而不实际运行它们,则可以为 migrate:rollback 命令提供 --pretend 标志:

shell
php artisan migrate:rollback --pretend

migrate:reset 命令将回滚应用程序的所有迁移:

shell
php artisan migrate:reset

使用单个命令回滚和迁移

migrate:refresh 命令将回滚您的所有迁移,然后执行 migrate 命令。此命令可以有效地重新创建整个数据库:

shell
php artisan migrate:refresh

# 刷新数据库并运行所有数据库种子...
php artisan migrate:refresh --seed

您可以通过为 refresh 命令提供 step 选项来回滚和重新迁移有限数量的迁移。例如,以下命令将回滚并重新迁移最后 5 次迁移:

shell
php artisan migrate:refresh --step=5

删除所有表并迁移

migrate:fresh 命令将从数据库中删除所有表,然后执行 migrate 命令:

shell
php artisan migrate:fresh

php artisan migrate:fresh --seed

默认情况下,migrate:fresh 命令仅从默认数据库连接中删除表。但是,您可以使用 --database 选项来指定应迁移的数据库连接。数据库连接名称应与应用程序的数据库配置文件中定义的连接相对应:

shell
php artisan migrate:fresh --database=admin

WARNING

migrate:fresh 命令将删除所有数据库表,无论其前缀如何。在与其他应用程序共享的数据库上进行开发时,应谨慎使用此命令。

Tables 表

创建表

要创建新的数据库表,请使用 Schema 外观上的 create 方法。create 方法接受两个参数:第一个是表的名称,而第二个是闭包,它接收可用于定义新表的 Blueprint 对象:

php
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;

    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('email');
        $table->timestamps();
    });

创建表时,您可以使用架构构建器的任何列方法来定义表的列。

确定 Table / Column 是否存在

您可以使用 hasTablehasColumnhasIndex 方法确定表、列或索引是否存在:

php
    if (Schema::hasTable('users')) {
        //  “users” 表存在...
    }

    if (Schema::hasColumn('users', 'email')) {
        // “users” 表存在并且有一个 “email” 列......
    }

    if (Schema::hasIndex('users', ['email'], 'unique')) {
        // “users” 表存在,并且在 “email” 列上具有唯一索引...
    }

数据库连接和表选项

如果要对不是应用程序默认连接的数据库连接执行架构操作,请使用 connection 方法:

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

此外,还可以使用一些其他属性和方法来定义表创建的其他方面。engine 属性可用于在使用 MariaDB 或 MySQL 时指定表的存储引擎:

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

        // ...
    });

在使用 MariaDB 或 MySQL 时,charsetcollation 属性可用于指定所创建表的字符集和排序规则:

php
    Schema::create('users', function (Blueprint $table) {
        $table->charset('utf8mb4');
        $table->collation('utf8mb4_unicode_ci');

        // ...
    });

temporary方法可用于指示表应该是 “临时的”。临时 table 仅对当前连接的数据库会话可见,并在连接关闭时自动删除:

php
    Schema::create('calculations', function (Blueprint $table) {
        $table->temporary();

        // ...
    });

如果你想向数据库表添加 “comment”,你可以在 table 实例上调用 comment 方法。表注释目前仅受 MariaDB、MySQL 和 PostgreSQL 支持:

php
    Schema::create('calculations', function (Blueprint $table) {
        $table->comment('Business calculations');

        // ...
    });

更新表

Schema Facade上的 table 方法可用于更新现有表。与 create 方法一样,table 方法接受两个参数:表的名称和接收 Blueprint 实例的闭包,您可以使用它来向表中添加列或索引:

php
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;

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

重命名/删除表

要重命名现有数据库表,请使用 rename 方法:

php
    use Illuminate\Support\Facades\Schema;

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

要删除现有表,您可以使用 dropdropIfExists 方法:

php
    Schema::drop('users');

    Schema::dropIfExists('users');

使用外键重命名表

在重命名表之前,您应该验证表上的任何外键约束在迁移文件中是否具有显式名称,而不是让 Laravel 分配基于约定的名称。否则,外键约束名称将引用旧的表名。

Columns 列

创建列

Schema facade上的 table 方法可用于更新现有表。与 create 方法一样,table 方法接受两个参数:表的名称和接收可用于向表中添加列 Illuminate\Database\Schema\Blueprint 的实例的闭包:

php
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;

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

可用的列类型

架构构建器蓝图提供了多种方法,这些方法对应于您可以添加到数据库表中的不同类型的列。下表列出了每种可用方法:

bigIncrements()

bigIncrements 方法创建一个自动递增的 UNSIGNED BIGINT(主键)等效列:

php
    $table->bigIncrements('id');

bigInteger()

bigInteger 方法创建一个 BIGINT 等效列:

php
    $table->bigInteger('votes');

binary()

binary 方法创建一个 BLOB 等效列:

php
    $table->binary('photo');

当使用 MySQL、MariaDB 或 SQL Server 时,您可以传递lengthfixed参数来创建 VARBINARYBINARY 等效列:

php
    $table->binary('data', length: 16); // VARBINARY(16)

    $table->binary('data', length: 16, fixed: true); // BINARY(16)

boolean()

boolean 方法创建一个 BOOLEAN 等效列:

php
    $table->boolean('confirmed');

char()

char 方法创建一个具有给定长度的 CHAR 等效列:

php
    $table->char('name', length: 100);

dateTimeTz()

dateTimeTz 方法创建一个 DATETIME(带时区)等效列,该列具有可选的秒小数精度:

php
    $table->dateTimeTz('created_at', precision: 0);

dateTime()

dateTime 方法创建具有可选秒小数精度的 DATETIME 等效列:

php
    $table->dateTime('created_at', precision: 0);

date()

date 方法会创建一个 DATE 等效列:

php
    $table->date('created_at');

decimal()

decimal 方法创建具有给定精度(总位数)和小数位数(十进制位数)的 DECIMAL 等效列:

php
    $table->decimal('amount', total: 8, places: 2);

double()

double 方法创建一个 DOUBLE 等效列:

php
    $table->double('amount');

enum()

enum 方法使用给定的有效值创建一个 ENUM 等效列:

php
    $table->enum('difficulty', ['easy', 'hard']);

float()

float 方法创建具有给定精度的 FLOAT 等效列:

php
    $table->float('amount', precision: 53);

foreignId()

foreignId 方法创建一个 UNSIGNED BIGINT 等效列:

php
    $table->foreignId('user_id');

foreignIdFor()

foreignIdFor 方法为给定的模型类添加一个 {column}_id 等效列。列类型将为 UNSIGNED BIGINT、``CHAR(36)CHAR(26),具体取决于模型键类型:

php
    $table->foreignIdFor(User::class);

foreignUlid()

foreignUlid 方法创建一个 ULID 等效列:

php
    $table->foreignUlid('user_id');

foreignUuid()

foreignUuid 方法创建一个 UUID 等效列:

php
    $table->foreignUuid('user_id');

geography()

geography 方法使用给定的空间类型和 SRID(空间参考系统标识符)创建一个 GEOGRAPHY 等效列:

php
    $table->geography('coordinates', subtype: 'point', srid: 4326);

NOTE

对空间类型的支持取决于您的数据库驱动程序。请参阅您的数据库文档。如果您的应用程序正在使用 PostgreSQL 数据库,则必须先安装 PostGIS 扩展,然后才能使用 geography 方法。

geometry()

geometry 方法将创建具有给定空间类型和 SRID(空间参考系统标识符)的 GEOMETRY 等效列:

php
    $table->geometry('positions', subtype: 'point', srid: 0);

NOTE

对空间类型的支持取决于您的数据库驱动程序。请参阅您的数据库文档。如果您的应用程序正在使用 PostgreSQL 数据库,则必须先安装 PostGIS 扩展,然后才能使用 geometry 方法。

id()

id 方法是 bigIncrements 方法的别名。默认情况下,该方法将创建一个 id 列;但是,如果您想为列分配不同的名称,则可以传递列名:

php
    $table->id();

increments()

increments 方法创建一个自动递增的 UNSIGNED INTEGER 等效列作为主键:

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

integer()

integer 方法创建一个 INTEGER 等效列:

php
    $table->integer('votes');

ipAddress()

ipAddress 方法创建一个 VARCHAR 等效列:

php
    $table->ipAddress('visitor');

使用 PostgreSQL 时,将创建一个 INET 列。

json()

json 方法会创建一个 JSON 等效列:

php
    $table->json('options');

jsonb()

jsonb 方法创建一个 JSONB 等效列:

php
    $table->jsonb('options');

longText()

longText 会创建一个 LONGTEXT 等效列:

php
    $table->longText('description');

使用 MySQL 或 MariaDB 时,您可以将二进制字符集应用于列,以便创建 LONGBLOB 等效列:

php
    $table->longText('data')->charset('binary'); // LONGBLOB

macAddress()

macAddress 方法创建一个用于保存 MAC 地址的列。某些数据库系统(如 PostgreSQL)具有此类数据的专用列类型。其他数据库系统将使用字符串等效列:

php
    $table->macAddress('device');

mediumIncrements()

mediumIncrements 方法创建一个自动递增的 UNSIGNED MEDIUMINT 等效列作为主键:

php
    $table->mediumIncrements('id');

mediumInteger()

mediumInteger 方法创建一个 MEDIUMINT 等效列:

php
    $table->mediumInteger('votes');

mediumText()

mediumText 方法创建一个 MEDIUMTEXT 等效列:

php
    $table->mediumText('description');

使用 MySQL 或 MariaDB 时,您可以将二进制字符集应用于列,以便创建 MEDIUMBLOB 等效列:

php
    $table->mediumText('data')->charset('binary'); // MEDIUMBLOB

morphs()

morphs 方法是一种便捷的方法,它添加一个 {column}_id 等效列和一个 {column}_type``VARCHAR 等效列。{column}_id 的列类型将为 UNSIGNED BIGINT、``CHAR(36)CHAR(26),具体取决于模型键类型。

此方法旨在用于定义多态 Eloquent 关系所需的列。在以下示例中,将创建 taggable_idtaggable_type 列:

php
    $table->morphs('taggable');

nullableTimestamps()

nullableTimestamps 方法是 timestamps 方法的别名:

php
    $table->nullableTimestamps(precision: 0);

nullableMorphs()

该方法类似于 morphs 方法;但是,创建的列将是 “nullable” 的:

php
    $table->nullableMorphs('taggable');

nullableUlidMorphs()

该方法类似于 ulidMorphs 方法;但是,创建的列将是 “nullable” 的:

php
    $table->nullableUlidMorphs('taggable');

nullableUuidMorphs()

该方法类似于 uuidMorphs 方法;但是,创建的列将是 “nullable” 的:

php
    $table->nullableUuidMorphs('taggable');

rememberToken()

rememberToken 方法创建一个可为空的 VARCHAR(100) 等效列,该列旨在存储当前的“记住我”身份验证令牌:

php
    $table->rememberToken();

set()

set 方法使用给定的有效值列表创建一个 SET 等效列:

php
    $table->set('flavors', ['strawberry', 'vanilla']);

smallIncrements()

smallIncrements 方法创建一个自动递增的 UNSIGNED SMALLINT 等效列作为主键:

php
    $table->smallIncrements('id');

smallInteger()

smallInteger 方法创建一个 SMALLINT 等效列:

php
    $table->smallInteger('votes');

softDeletesTz()

softDeletesTz 方法添加一个可为 null 的 deleted_at``TIMESTAMP(带时区)等效列,该列具有可选的秒小数部分精度。此列旨在存储 Eloquent 的“软删除”功能所需的 deleted_at 时间戳:

php
    $table->softDeletesTz('deleted_at', precision: 0);

softDeletes()

softDeletes 方法添加了一个可为 null 的 deleted_at``TIMESTAMP 等效列,该列具有可选的秒小数部分精度。此列旨在存储 Eloquent 的“软删除”功能所需的deleted_at时间戳:

php
    $table->softDeletes('deleted_at', precision: 0);

string()

string 方法创建给定长度的 VARCHAR 等效列:

php
    $table->string('name', length: 100);

text()

text 方法创建一个 TEXT 等效列:

php
    $table->text('description');

使用 MySQL 或 MariaDB 时,您可以将二进制字符集应用于列,以便创建 BLOB 等效列:

php
    $table->text('data')->charset('binary'); // BLOB

timeTz()

timeTz 方法创建一个 TIME(带时区)等效列,该列具有可选的秒小数精度:

php
    $table->timeTz('sunrise', precision: 0);

time()

time 方法会创建一个 TIME 等效列,该列具有可选的秒小数精度:

php
    $table->time('sunrise', precision: 0);

timestampTz()

timestampTz 方法创建一个 TIMESTAMP(带时区)等效列,该列具有可选的小数秒精度:

php
    $table->timestampTz('added_at', precision: 0);

timestamp()

timestamp 方法会创建一个 TIMESTAMP 等效列,该列具有可选的秒小数部分精度:

php
    $table->timestamp('added_at', precision: 0);

timestampsTz()

timestampsTz 方法创建created_atupdated_at``TIMESTAMP(带时区)等效列,并具有可选的秒小数精度:

php
    $table->timestampsTz(precision: 0);

timestamps()

timestamps 方法创建具有可选秒小数精度的 created_atupdated_at``TIMESTAMP 等效列:

php
    $table->timestamps(precision: 0);

tinyIncrements()

tinyIncrements 方法创建一个自动递增的 UNSIGNED TINYINT 等效列作为主键:

php
    $table->tinyIncrements('id');

tinyInteger()

tinyInteger 方法创建一个 TINYINT 等效列:

php
    $table->tinyInteger('votes');

tinyText()

tinyText 方法创建一个 TINYTEXT 等效列:

php
    $table->tinyText('notes');

使用 MySQL 或 MariaDB 时,您可以将二进制字符集应用于该列,以便创建 TINYBLOB 等效列:

php
    $table->tinyText('data')->charset('binary'); // TINYBLOB

unsignedBigInteger()

unsignedBigInteger 方法创建一个 UNSIGNED BIGINT 等效列:

php
    $table->unsignedBigInteger('votes');

unsignedInteger()

unsignedInteger 方法创建一个 UNSIGNED INTEGER 等效列:

php
    $table->unsignedInteger('votes');

unsignedMediumInteger()

unsignedMediumInteger 方法创建一个 UNSIGNED MEDIUMINT 等效列:

php
    $table->unsignedMediumInteger('votes');

unsignedSmallInteger()

unsignedSmallInteger 方法创建一个 UNSIGNED SMALLINT 等效列:

php
    $table->unsignedSmallInteger('votes');

unsignedTinyInteger()

unsignedTinyInteger 方法创建一个 UNSIGNED TINYINT 等效列:

php
    $table->unsignedTinyInteger('votes');

ulidMorphs()

ulidMorphs 方法是一种便捷的方法,它添加一个 {column}_id``CHAR(26) 等效列和一个 {column}_type``VARCHAR 等效列。

此方法旨在用于定义使用 ULID 标识符的多态 Eloquent 关系所需的列。在以下示例中,将创建 taggable_idtaggable_type 列:

php
    $table->ulidMorphs('taggable');

uuidMorphs()

uuidMorphs 方法是一种便捷的方法,它添加一个 {column}_id``CHAR(36) 等效列和一个 {column}_type``VARCHAR 等效列。

在定义使用 UUID 标识符的多态 Eloquent 关系所需的列时,可以使用此方法。在以下示例中,将创建 taggable_idtaggable_type 列:

php
    $table->uuidMorphs('taggable');

ulid()

ulid 方法将创建一个 ULID 等效列:

php
    $table->ulid('id');

uuid()

uuid 方法创建一个 UUID 等效列:

php
    $table->uuid('id');

year()

year 方法创建一个 YEAR 等效列:

php
    $table->year('birth_year');

Column Modifiers

除了上面列出的列类型之外,在向数据库表添加列时,还可以使用几个列 “修饰符”。例如,要使列 “nullable” ,你可以使用 nullable 方法:

php
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;

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

下表包含所有可用的列修饰符。此列表不包括索引修饰符:

修饰语描述
->after('column')Place the column "after" another column (MariaDB / MySQL).
->autoIncrement()Set INTEGER columns as auto-incrementing (primary key).
->charset('utf8mb4')Specify a character set for the column (MariaDB / MySQL).
->collation('utf8mb4_unicode_ci')Specify a collation for the column.
->comment('my comment')Add a comment to a column (MariaDB / MySQL / PostgreSQL).
->default($value)Specify a "default" value for the column.
->first()Place the column "first" in the table (MariaDB / MySQL).
->from($integer)Set the starting value of an auto-incrementing field (MariaDB / MySQL / PostgreSQL).
->invisible()Make the column "invisible" to SELECT * queries (MariaDB / MySQL).
->nullable($value = true)Allow NULL values to be inserted into the column.
->storedAs($expression)Create a stored generated column (MariaDB / MySQL / PostgreSQL / SQLite).
->unsigned()Set INTEGER columns as UNSIGNED (MariaDB / MySQL).
->useCurrent()Set TIMESTAMP columns to use CURRENT_TIMESTAMP as default value.
->useCurrentOnUpdate()Set TIMESTAMP columns to use CURRENT_TIMESTAMP when a record is updated (MariaDB / MySQL).
->virtualAs($expression)Create a virtual generated column (MariaDB / MySQL / SQLite).
->generatedAs($expression)Create an identity column with specified sequence options (PostgreSQL).
->always()Defines the precedence of sequence values over input for an identity column (PostgreSQL).

默认表达式

default 修饰符接受值或 Illuminate\Database\Query\Expression 实例。使用 Expression 实例将阻止 Laravel 将值括在引号中,并允许您使用特定于数据库的函数。这特别有用的一种情况是,当您需要为 JSON 列分配默认值时:

php
    <?php

    use Illuminate\Support\Facades\Schema;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Database\Query\Expression;
    use Illuminate\Database\Migrations\Migration;

    return new class extends Migration
    {
        /**
         * 运行迁移
         */
        public function up(): void
        {
            Schema::create('flights', function (Blueprint $table) {
                $table->id();
                $table->json('movies')->default(new Expression('(JSON_ARRAY())'));
                $table->timestamps();
            });
        }
    };

WARNING

对默认表达式的支持取决于您的数据库驱动程序、数据库版本和字段类型。请参阅您的数据库文档。

列顺序

当使用 MariaDB 或 MySQL 数据库时,after 方法可用于在架构中的现有列之后添加列:

php
    $table->after('password', function (Blueprint $table) {
        $table->string('address_line1');
        $table->string('address_line2');
        $table->string('city');
    });

修改列

change 方法允许您修改现有列的类型和属性。例如,您可能希望增加字符串列的大小。要查看 change 方法的实际效果,让我们将 name 列的大小从 25 增加到 50。为此,我们只需定义列的新状态,然后调用 change 方法:

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

修改列时,必须显式包含要在列定义中保留的所有修饰符 - 任何缺少的属性都将被删除。例如,要保留 unsigneddefaultcomment 属性,必须在更改列时显式调用每个修饰符:

php
    Schema::table('users', function (Blueprint $table) {
        $table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
    });

change 方法不会更改列的索引。因此,在修改列时,您可以使用索引修饰符显式添加或删除索引:

php
// 添加索引...
$table->bigIncrements('id')->primary()->change();

// 删除索引...
$table->char('postal_code', 10)->unique(false)->change();

重命名列

要重命名列,您可以使用架构构建器提供的 renameColumn 方法:

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

删除列

要删除列,您可以在架构构建器上使用 dropColumn 方法:

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

您可以通过将列名数组传递给 dropColumn 方法,从表中删除多个列:

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

可用的命令别名

Laravel 提供了几种与删除常见类型的列相关的便捷方法。下表描述了每种方法:

CommandDescription
$table->dropMorphs('morphable');删除 morphable_id and morphable_type 列.
$table->dropRememberToken();删除 remember_token 列.
$table->dropSoftDeletes();删除 deleted_at 列.
$table->dropSoftDeletesTz();dropSoftDeletes() 方法的别名.
$table->dropTimestamps();删除 created_at and updated_at 列.
$table->dropTimestampsTz();dropTimestamps() 方法的别名.

索引

创建索引

Laravel 架构构建器支持多种类型的索引。以下示例创建一个新的 email 列,并指定其值应是唯一的。要创建索引,我们可以将 unique 方法链接到列定义上:

php
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;

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

或者,您可以在定义列后创建索引。为此,您应该在架构构建器蓝图上调用 unique 方法。此方法接受应接收唯一索引的列的名称:

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

您甚至可以将列数组传递给 index 方法以创建复合(或复合)索引:

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

创建索引时,Laravel 将根据表、列名和索引类型自动生成索引名称,但你可以将第二个参数传递给该方法以自己指定索引名称:

php
    $table->unique('email', 'unique_email');

可用的索引类型

Laravel 的 schema builder 蓝图类提供了用于创建 Laravel 支持的每种索引类型的方法。每个 index 方法都接受可选的第二个参数来指定索引的名称。如果省略,则名称将从用于索引的表和列的名称以及索引类型派生。下表描述了每种可用的索引方法:

命令描述
$table->primary('id');添加主键
$table->primary(['id', 'parent_id']);添加组合键
$table->unique('email');添加唯一索引
$table->index('state');添加索引
$table->fullText('body');添加全文索引 (MariaDB / MySQL / PostgreSQL)
$table->fullText('body')->language('english');添加指定语言 (PostgreSQL) 的全文索引
$table->spatialIndex('location');添加空间索引(SQLite 除外)

重命名索引

要重命名索引,您可以使用 renameIndex 架构构建器蓝图提供的方法。此方法接受当前索引名称作为其第一个参数,将所需名称作为其第二个参数:

php
    $table->renameIndex('from', 'to')

删除索引

要删除索引,必须指定索引的名称。默认情况下,Laravel 会根据表名、索引列的名称和索引类型自动分配索引名称。以下是一些示例:

命令描述
$table->dropPrimary('users_id_primary');从 “users” 表中删除主键
$table->dropUnique('users_email_unique');从 “users” 表中删除唯一索引
$table->dropIndex('geo_state_index');从 “geo” 表中删除基本索引
$table->dropFullText('posts_body_fulltext');从 “posts” 表中删除全文索引
$table->dropSpatialIndex('geo_location_spatialindex');从 “geo” 表中删除空间索引(SQLite 除外)

如果你将列数组传递给一个删除索引的方法,那么将根据表名、列和索引类型生成常规索引名称:

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

外键约束

Laravel 还支持创建外键约束,这些约束用于在数据库级别强制引用完整性。例如,让我们在 posts 表上定义一个 user_id 列,该列引用 users 表上的 id 列:

php
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;

    Schema::table('posts', function (Blueprint $table) {
        $table->unsignedBigInteger('user_id');

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

由于此语法相当冗长,因此 Laravel 提供了其他更简洁的方法,这些方法使用约定来提供更好的开发人员体验。当使用 foreignId 方法创建列时,上面的示例可以重写如下:

php
    Schema::table('posts', function (Blueprint $table) {
        $table->foreignId('user_id')->constrained();
    });

foreignId 方法创建一个 UNSIGNED BIGINT 等效列,而 constrained 方法将使用约定来确定被引用的表和列。如果你的表名与 Laravel 的约定不匹配,你可以手动将其提供给 constrained 方法。此外,还可以指定应分配给生成索引的名称:

php
    Schema::table('posts', function (Blueprint $table) {
        $table->foreignId('user_id')->constrained(
            table: 'users', indexName: 'posts_user_id'
        );
    });

您还可以为约束的 “on delete” 和 “on update” 属性指定所需的操作:

php
    $table->foreignId('user_id')
          ->constrained()
          ->onUpdate('cascade')
          ->onDelete('cascade');

还为这些操作提供了另一种富有表现力的语法:

MethodDescription
$table->cascadeOnUpdate();更新应级联
$table->restrictOnUpdate();应限制更新
$table->noActionOnUpdate();对更新不执行任何操作
$table->cascadeOnDelete();删除应级联
$table->restrictOnDelete();应限制删除
$table->nullOnDelete();删除操作应将外键值设置为 null

必须在 constrained 方法之前调用任何其他列修饰符:

php
    $table->foreignId('user_id')
          ->nullable()
          ->constrained();

删除外键

要删除外键,您可以使用 dropForeign 方法,将要删除的外键约束的名称作为参数传递。外键约束使用与索引相同的命名约定。换句话说,外键约束名称基于表的名称和约束中的列,后跟“_foreign”后缀:

php
    $table->dropForeign('posts_user_id_foreign');

或者,你可以将一个包含保存外键的列名的数组传递给 dropForeign 方法。该数组将使用 Laravel 的约束命名约定转换为外键约束名称:

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

切换外键约束

您可以使用以下方法在迁移中启用或禁用外键约束:

php
    Schema::enableForeignKeyConstraints();

    Schema::disableForeignKeyConstraints();

    Schema::withoutForeignKeyConstraints(function () {
        // 在此闭包中禁用了约束...
    });

WARNING

SQLite 默认禁用外键约束。使用 SQLite 时,请确保在数据库配置中启用外键支持,然后再尝试在迁移中创建外键支持。

事件

为方便起见,每个迁移操作都将调度一个事件。以下所有事件都扩展了基 Illuminate\Database\Events\MigrationEvent 类:

描述
Illuminate\Database\Events\MigrationsStarted即将执行一批迁移
Illuminate\Database\Events\MigrationsEnded一批迁移已完成执行
Illuminate\Database\Events\MigrationStarted即将执行单个迁移
Illuminate\Database\Events\MigrationEnded单个迁移已完成执行
Illuminate\Database\Events\NoPendingMigrations迁移命令未找到待处理的迁移
Illuminate\Database\Events\SchemaDumped数据库架构转储已完成
Illuminate\Database\Events\SchemaLoaded已加载现有数据库架构转储