laravel
7. 数据库
数据库:迁移

介绍

迁移就像是您数据库的版本控制,允许您的团队定义和共享应用程序的数据库模式定义。如果您曾经不得不告诉队友在从源代码控制中拉取您的更改后,手动将列添加到他们的本地数据库模式中,那么您就面临了数据库迁移所解决的问题。

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

生成迁移

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

php artisan make:migration create_flights_table

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

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

[!注意]
可以使用 存根发布 自定义迁移存根。

合并迁移

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

php artisan schema:dump
 
# 转储当前数据库模式并修剪所有现有的迁移...
php artisan schema:dump --prune

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

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

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

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

[!警告]
迁移合并仅适用于 MariaDB、MySQL、PostgreSQL 和 SQLite 数据库,并利用数据库的命令行客户端。

迁移结构

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

在这两个方法中,您可以使用 Laravel 模式构建器来明确地创建和修改表。要了解 Schema 构建器上的所有可用方法,查看其文档。例如,以下迁移创建一个 flights 表:

<?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 属性:

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

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

运行迁移

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

php artisan migrate

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

php artisan migrate:status

如果您想在不实际运行迁移的情况下查看迁移将执行的 SQL 语句,您可以向 migrate 命令提供 --pretend 标志:

php artisan migrate --pretend

隔离迁移执行

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

当提供 isolated 选项时,Laravel 将在尝试运行您的迁移之前使用您的应用程序的缓存驱动程序获取一个原子锁。在该锁被持有期间,所有其他尝试运行 migrate 命令的操作都不会执行;但是,该命令仍将以成功的退出状态代码退出:

php artisan migrate --isolated

[!警告]
要使用此功能,您的应用程序必须使用 memcachedredisdynamodbdatabasefilearray 缓存驱动程序作为您的应用程序的默认缓存驱动程序。此外,所有服务器必须与相同的中央缓存服务器进行通信。

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

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

php artisan migrate --force

回滚迁移

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

php artisan migrate:rollback

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

php artisan migrate:rollback --step=5

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

php artisan migrate:rollback --batch=3

如果您想在不实际运行迁移的情况下查看迁移将执行的 SQL 语句,您可以向 migrate:rollback 命令提供 --pretend 标志:

php artisan migrate:rollback --pretend

migrate: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

删除所有表并迁移

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

php artisan migrate:fresh
 
php artisan migrate:fresh --seed

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

php artisan migrate:fresh --database=admin

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

创建表

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

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();
});

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

确定表/列存在

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

if (Schema::hasTable('users')) {
    // "users" 表存在...
}

if (Schema::hasColumn('users', 'email')) {
    // "users" 表存在且具有 "email" 列...
}

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

数据库连接和表选项

如果您想在不是您的应用程序的默认连接的数据库连接上执行模式操作,请使用 connection 方法:

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

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

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

    //...
});

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

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

    //...
});

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

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

    //...
});

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

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

    //...
});

更新表

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

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

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

重命名/删除表

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

use Illuminate\Support\Facades\Schema;

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

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

Schema::drop('users');

Schema::dropIfExists('users');

重命名带有外键的表

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

创建列

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

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

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

可用的列类型

模式构建器蓝图提供了多种方法,这些方法与您可以添加到数据库表中的不同类型的列相对应。下面的表格列出了所有可用的方法:

bigIncrements() {.collection-method.first-collection-method}

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

$table->bigIncrements('id');

bigInteger() {.collection-method}

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

$table->bigInteger('votes');

binary() {.collection-method}

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

$table->binary('photo');

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

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

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

boolean() {.collection-method}

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

$table->boolean('confirmed');

char() {.collection-method}

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

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

dateTimeTz() {.collection-method}

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

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

dateTime() {.collection-method}

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

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

date() {.collection-method}

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

$table->date('created_at');

decimal() {.collection-method}

decimal方法创建一个具有给定精度(总数字)和小数位数(decimal digits)的DECIMAL等效列:

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

double() {.collection-method}

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

$table->double('amount');

enum() {.collection-method}

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

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

float() {.collection-method}

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

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

foreignId() {.collection-method}

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

$table->foreignId('user_id');

foreignIdFor() {.collection-method}

foreignIdFor方法为给定的模型类添加一个{column}_id等效列。根据模型键类型,列类型将是UNSIGNED BIGINTCHAR(36)CHAR(26)

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

foreignUlid() {.collection-method}

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

$table->foreignUlid('user_id');

foreignUuid() {.collection-method}

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

$table->foreignUuid('user_id');

geography() {.collection-method}

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

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

[!NOTE]
对空间类型的支持取决于您的数据库驱动程序。请参考您的数据库文档。如果您的应用程序使用 PostgreSQL 数据库,在使用geography方法之前,您必须安装PostGIS (opens in a new tab)扩展。

geometry() {.collection-method}

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

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

[!NOTE]
对空间类型的支持取决于您的数据库驱动程序。请参考您的数据库文档。如果您的应用程序使用 PostgreSQL 数据库,在使用geometry方法之前,您必须安装PostGIS (opens in a new tab)扩展。

id() {.collection-method}

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

$table->id();

increments() {.collection-method}

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

$table->increments('id');

integer() {.collection-method}

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

$table->integer('votes');

ipAddress() {.collection-method}

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

$table->ipAddress('visitor');

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

json() {.collection-method}

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

$table->json('options');

jsonb() {.collection-method}

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

$table->jsonb('options');

longText() {.collection-method}

longText方法创建一个LONGTEXT等效列:

$table->longText('description');

在使用 MySQL 或 MariaDB 时,您可以为该列应用一个binary字符集,以创建一个LONGBLOB等效列:

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

macAddress() {.collection-method}

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

$table->macAddress('device');

mediumIncrements() {.collection-method}

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

$table->mediumIncrements('id');

mediumInteger() {.collection-method}

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

$table->mediumInteger('votes');

mediumText() {.collection-method}

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

$table->mediumText('description');

在使用 MySQL 或 MariaDB 时,您可以为该列应用一个binary字符集,以创建一个MEDIUMBLOB等效列:

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

morphs() {.collection-method}

morphs方法是一个便利方法,它添加一个{column}_id等效列和一个{column}_type VARCHAR等效列。根据模型键类型,{column}_id的列类型将是UNSIGNED BIGINTCHAR(36)CHAR(26)

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

$table->morphs('taggable');

nullableTimestamps() {.collection-method}

nullableTimestamps方法是timestamps方法的别名:

$table->nullableTimestamps(precision: 0);

nullableMorphs() {.collection-method}

该方法类似于morphs方法;然而,创建的列将是“可空的”:

$table->nullableMorphs('taggable');

nullableUlidMorphs() {.collection-method}

该方法类似于ulidMorphs方法;然而,创建的列将是“可空的”:

$table->nullableUlidMorphs('taggable');

nullableUuidMorphs() {.collection-method}

该方法类似于uuidMorphs方法;然而,创建的列将是“可空的”:

$table->nullableUuidMorphs('taggable');

rememberToken() {.collection-method}

rememberToken方法创建一个可空的、VARCHAR(100)等效列,用于存储当前的“记住我”认证令牌

$table->rememberToken();

set() {.collection-method}

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

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

smallIncrements() {.collection-method}

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

$table->smallIncrements('id');

smallInteger() {.collection-method}

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

$table->smallInteger('votes');

softDeletesTz() {.collection-method}

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

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

softDeletes() {.collection-method}

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

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

string() {.collection-method}

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

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

text() {.collection-method}

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

$table->text('description');

在使用 MySQL 或 MariaDB 时,您可以为该列应用一个binary字符集,以创建一个BLOB等效列:

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

timeTz() {.collection-method}

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

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

time() {.collection-method}

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

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

timestampTz() {.collection-method}

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

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

timestamp() {.collection-method}

timestamp方法创建一个带有可选的小数秒精度的TIMESTAMP等效列:

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

timestampsTz() {.collection-method}

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

$table->timestampsTz(precision: 0);

timestamps() {.collection-method}

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

$table->timestamps(precision: 0);

tinyIncrements() {.collection-method}

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

$table->tinyIncrements('id');

tinyInteger() {.collection-method}

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

$table->tinyInteger('votes');

tinyText() {.collection-method}

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

$table->tinyText('notes');

在使用 MySQL 或 MariaDB 时,您可以为该列应用一个binary字符集,以创建一个TINYBLOB等效列:

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

unsignedBigInteger() {.collection-method}

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

$table->unsignedBigInteger('votes');

unsignedInteger() {.collection-method}

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

$table->unsignedInteger('votes');

`

列修饰符

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

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('users', function (Blueprint $table) {
    $table->string('email')->nullable();
});

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

修饰符描述
->after('column')将列放置在另一列“之后”(MariaDB / MySQL)。
->autoIncrement()INTEGER 列设置为自动递增(主键)。
->charset('utf8mb4')为列指定字符集(MariaDB / MySQL)。
->collation('utf8mb4_unicode_ci')为列指定排序规则。
->comment('my comment')为列添加注释(MariaDB / MySQL / PostgreSQL)。
->default($value)为列指定“默认”值。
->first()将列放置在表的“首位”(MariaDB / MySQL)。
->from($integer)设置自动递增字段的起始值(MariaDB / MySQL / PostgreSQL)。
->invisible()使列对 SELECT * 查询“不可见”(MariaDB / MySQL)。
->nullable($value = true)允许将 NULL 值插入到列中。
->storedAs($expression)创建一个存储生成列(MariaDB / MySQL / PostgreSQL / SQLite)。
->unsigned()INTEGER 列设置为 UNSIGNED(MariaDB / MySQL)。
->useCurrent()TIMESTAMP 列设置为使用 CURRENT_TIMESTAMP 作为默认值。
->useCurrentOnUpdate()当记录更新时,将 TIMESTAMP 列设置为使用 CURRENT_TIMESTAMP(MariaDB / MySQL)。
->virtualAs($expression)创建一个虚拟生成列(MariaDB / MySQL / SQLite)。
->generatedAs($expression)创建具有指定序列选项的标识列(PostgreSQL)。
->always()为标识列定义序列值相对于输入的优先级(PostgreSQL)。

默认表达式

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

<?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();
        });
    }
};

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

列顺序

当使用 MariaDB 或 MySQL 数据库时,可以使用 after 方法在模式中现有列之后添加列:

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

修改列

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

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

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

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

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

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

重命名列

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

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

删除列

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

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

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

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

可用的命令别名

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

命令描述
$table->dropMorphs('morphable');删除 morphable_idmorphable_type 列。
$table->dropRememberToken();删除 remember_token 列。
$table->dropSoftDeletes();删除 deleted_at 列。
$table->dropSoftDeletesTz();dropSoftDeletes() 方法的别名。
$table->dropTimestamps();删除 created_atupdated_at 列。
$table->dropTimestampsTz();dropTimestamps() 方法的别名。

索引

创建索引

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

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('users', function (Blueprint $table) {
    $table->string('email')->unique();
});

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

$table->unique('email');

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

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

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

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

可用的索引类型

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

命令描述
$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 方法。该方法接受当前索引名称作为其第一个参数,所需名称作为其第二个参数:

$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 除外)。

如果您将列数组传递到删除索引的方法中,将根据表名、列和索引类型生成常规索引名称:

Schema::table('geo', function (Blueprint $table) {
    $table->dropIndex(['state']); // 删除索引 'geo_state_index'
});

外键约束

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

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 方法创建您的列时,上面的示例可以重写如下:

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

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

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

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

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

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

方法描述
$table->cascadeOnUpdate();更新应级联。
$table->restrictOnUpdate();更新应受到限制。
$table->noActionOnUpdate();更新时不采取行动。
$table->cascadeOnDelete();删除应级联。
$table->restrictOnDelete();删除应受到限制。
$table->nullOnDelete();删除应将外键值设置为 NULL

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

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

删除外键

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

$table->dropForeign('posts_user_id_foreign');

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

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

切换外键约束

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

Schema::enableForeignKeyConstraints();
 
Schema::disableForeignKeyConstraints();
 
Schema::withoutForeignKeyConstraints(function () {
    // 在这个闭包内约束被禁用...
});

[!警告]
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已加载现有的数据库模式转储。