Skip to content

数据库:迁移

介绍

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

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

生成迁移

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

shell
php artisan make:migration create_flights_table

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

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

lightbulb

可以使用 stub 发布 自定义迁移存根。

压缩迁移

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

shell
php artisan schema:dump

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

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

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

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

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

exclamation

迁移压缩仅适用于 MySQL、PostgreSQL 和 SQLite 数据库,并利用数据库的命令行客户端。架构转储可能无法恢复到内存中的 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
{
    /**
     * 运行迁移。
     *
     * @return void
     */
    public function up()
    {
        Schema::create('flights', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('airline');
            $table->timestamps();
        });
    }

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

设置迁移连接

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

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

/**
 * 运行迁移。
 *
 * @return void
 */
public function up()
{
    //
}

运行迁移

要运行所有未完成的迁移,请执行 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 命令的操作都不会执行;但是,命令仍将以成功的退出状态代码退出:

shell
php artisan migrate --isolated
exclamation

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

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

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

shell
php artisan migrate --force

回滚迁移

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

shell
php artisan migrate:rollback

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

shell
php artisan migrate:rollback --step=5

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

shell
php artisan migrate:reset

使用单个命令回滚并迁移

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

shell
php artisan migrate:refresh

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

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

shell
php artisan migrate:refresh --step=5

删除所有表并迁移

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

shell
php artisan migrate:fresh

php artisan migrate:fresh --seed
exclamation

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

创建表

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

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

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

});


创建表时,您可以使用架构构建器的任何[列方法](#creating-columns)来定义表的列。

<a id="checking-for-table-column-existence"></a>
#### 检查表/列是否存在

您可以使用 `hasTable` 和 `hasColumn` 方法检查表或列是否存在:

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

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

数据库连接和表选项

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

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

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

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

    // ...
});

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

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

    // ...
});

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

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

    // ...
});

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

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) {
```php
$table->integer('votes');

});


<a id="renaming-and-dropping-tables"></a>
### 重命名/删除表

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

```php
use Illuminate\Support\Facades\Schema;

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

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

php
Schema::drop('users');

Schema::dropIfExists('users');

重命名具有外键的表

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

创建列

可以在 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');

boolean()

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

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

char()

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

php
$table->char('name', 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', $precision = 8, $scale = 2);

double()

double 方法创建一个 DOUBLE 等效列,具有给定的精度(总位数)和小数位数:

php
$table->double('amount', 8, 2);

enum()

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

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

float()

float 方法创建一个 FLOAT 等效列,具有给定的精度(总位数)和小数位数:

php
$table->float('amount', 8, 2);

foreignId()

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

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

foreignIdFor()

foreignIdFor 方法为给定的模型类添加一个 {column}_id UNSIGNED BIGINT 等效列:

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

foreignUlid()

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

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

foreignUuid()

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

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

geometryCollection()

geometryCollection 方法创建一个 GEOMETRYCOLLECTION 等效列:

php
$table->geometryCollection('positions');

geometry()

geometry 方法创建一个 GEOMETRY 等效列:

php
$table->geometry('positions');

id()

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

$table->id();

increments()

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

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

integer()

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

$table->integer('votes');

ipAddress()

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

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

json()

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

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

jsonb()

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

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

lineString()

lineString 方法创建一个 LINESTRING 等效列:

php
$table->lineString('positions');

longText()

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

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

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');

morphs()

morphs 方法是一个便捷方法,添加一个 {column}_id UNSIGNED BIGINT 等效列和一个 {column}_type VARCHAR 等效列。

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

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

multiLineString()

multiLineString 方法创建一个 MULTILINESTRING 等效列:

php
$table->multiLineString('positions');

multiPoint()

multiPoint 方法创建一个 MULTIPOINT 等效列:

php
$table->multiPoint('positions');

multiPolygon()

multiPolygon 方法创建一个 MULTIPOLYGON 等效列:

php
$table->multiPolygon('positions');

nullableTimestamps()

nullableTimestamps 方法是 timestamps 方法的别名:

php
$table->nullableTimestamps(0);

nullableMorphs()

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

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

nullableUlidMorphs()

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

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

nullableUuidMorphs()

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

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

point()

point 方法创建一个 POINT 等效列:

php
$table->point('position');

polygon()

polygon 方法创建一个 POLYGON 等效列:

php
$table->polygon('position');

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 方法添加一个可为空的 deleted_at TIMESTAMP(带时区)等效列,具有可选的精度(总位数)。此列旨在存储 Eloquent 的“软删除”功能所需的 deleted_at 时间戳:

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

softDeletes()

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

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

string()

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

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

text()

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

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

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');

unsignedBigInteger()

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

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

unsignedDecimal()

unsignedDecimal 方法创建一个 UNSIGNED DECIMAL 等效列,具有可选的精度(总位数)和小数位数:

php
$table->unsignedDecimal('amount', $precision = 8, $scale = 2);

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');

列修饰符

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

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

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

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

修饰符描述
->after('column')将列放置在另一个列“之后”(MySQL)。
->autoIncrement()将 INTEGER 列设置为自增(主键)。
->charset('utf8mb4')为列指定字符集(MySQL)。
->collation('utf8mb4_unicode_ci')为列指定排序规则(MySQL/PostgreSQL/SQL Server)。
->comment('my comment')为列添加注释(MySQL/PostgreSQL)。
->default($value)为列指定“默认”值。
->first()将列放置在表的“首位”(MySQL)。
->from($integer)设置自增字段的起始值(MySQL / PostgreSQL)。
->invisible()使列对 SELECT * 查询“不可见”(MySQL)。
->nullable($value = true)允许在列中插入 NULL 值。
->storedAs($expression)创建存储生成的列(MySQL / PostgreSQL)。
->unsigned()将 INTEGER 列设置为 UNSIGNED(MySQL)。
->useCurrent()将 TIMESTAMP 列设置为使用 CURRENT_TIMESTAMP 作为默认值。
->useCurrentOnUpdate()将 TIMESTAMP 列设置为在记录更新时使用 CURRENT_TIMESTAMP。
->virtualAs($expression)创建虚拟生成的列(MySQL / PostgreSQL / SQLite)。
->generatedAs($expression)使用指定的序列选项创建标识列(PostgreSQL)。
->always()定义序列值相对于输入的优先级(PostgreSQL)。
->isGeometry()将空间列类型设置为 geometry - 默认类型为 geography(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
{
    /**
     * 运行迁移。
     *
     * @return void
     */
    public function up()
    {
        Schema::create('flights', function (Blueprint $table) {
            $table->id();
            $table->json('movies')->default(new Expression('(JSON_ARRAY())'));
            $table->timestamps();
        });
    }
};
exclamation

默认表达式的支持取决于您的数据库驱动程序、数据库版本和字段类型。请参阅数据库的文档。此外,无法将原始 default 表达式(使用 DB::raw)与通过 change 方法的列更改结合使用。

列顺序

使用 MySQL 数据库时,可以使用 after 方法在架构中将列添加到现有列之后:

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

修改列

先决条件

在修改列之前,您必须使用 Composer 包管理器安装 doctrine/dbal 包。Doctrine DBAL 库用于确定列的当前状态并创建所需的 SQL 查询以对列进行请求的更改:

php
composer require doctrine/dbal

如果您计划修改使用 timestamp 方法创建的列,还必须在应用程序的 config/database.php 配置文件中添加以下配置:

php
use Illuminate\Database\DBAL\TimestampType;

'dbal' => [
    'types' => [
        'timestamp' => TimestampType::class,
    ],
],
exclamation

如果您的应用程序正在使用 Microsoft SQL Server,请确保安装 doctrine/dbal:^3.0

更新列属性

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

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

我们还可以将列修改为可为空:

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

可以修改以下列类型:bigIntegerbinarybooleanchardatedateTimedateTimeTzdecimaldoubleintegerjsonlongTextmediumTextsmallIntegerstringtexttimetinyTextunsignedBigIntegerunsignedIntegerunsignedSmallIntegeruuid。要修改 timestamp 列类型,必须注册 Doctrine 类型

重命名列

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

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

在旧版数据库上重命名列

如果您运行的数据库安装版本低于以下版本之一,您应该确保在重命名列之前通过 Composer 包管理器安装 doctrine/dbal 库:

  • MySQL < 8.0.3
  • MariaDB < 10.5.2
  • SQLite < 3.25.0

删除列

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

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

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

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

在旧版数据库上删除列

如果您运行的 SQLite 版本低于 3.35.0,则必须通过 Composer 包管理器安装 doctrine/dbal 包,然后才能使用 dropColumn 方法。使用此包时,在单个迁移中删除或修改多个列不受支持。

可用命令别名

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 方法链接到列定义上:

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');

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

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

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

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

可用索引类型

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

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

索引长度和 MySQL / MariaDB

默认情况下,Laravel 使用 utf8mb4 字符集。如果您运行的 MySQL 版本低于 5.7.7 或 MariaDB 版本低于 10.2.2,您可能需要手动配置迁移生成的默认字符串长度,以便 MySQL 为其创建索引。您可以通过在 App\Providers\AppServiceProvider 类的 boot 方法中调用 Schema::defaultStringLength 方法来配置默认字符串长度:

php
use Illuminate\Support\Facades\Schema;

/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

或者,您可以为数据库启用 innodb_large_prefix 选项。有关如何正确启用此选项的说明,请参阅数据库的文档。

重命名索引

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

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

如果您的应用程序正在使用 SQLite 数据库,您必须通过 Composer 包管理器安装 doctrine/dbal 包,然后才能使用 renameIndex 方法。

删除索引

要删除索引,您必须指定索引的名称。默认情况下,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']); // 删除索引 '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('users');
});

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

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

还提供了一种替代的、表达性语法用于这些操作:

方法描述
$table->cascadeOnUpdate();更新应级联。
$table->restrictOnUpdate();更新应受限。
$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 () {
    // 在此闭包中禁用约束...
});
exclamation

SQLite 默认禁用外键约束。使用 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\SchemaDumped数据库架构转储已完成。
Illuminate\Database\Events\SchemaLoaded已加载现有数据库架构转储。