跳至内容

数据库:迁移

介绍

迁移就像数据库的版本控制,允许你的团队定义和共享应用程序的数据库模式。如果你曾经在从源代码控制中提取更改后,不得不告诉队友手动向其本地数据库模式添加一列,那么你遇到的问题正是数据库迁移可以解决的。

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

生成迁移

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

1php artisan make:migration create_flights_table

Laravel 会根据迁移的名称尝试猜测表的名称,并判断迁移是否会创建新表。如果 Laravel 能够根据迁移名称确定表名,则会将指定的表预填充到生成的迁移文件中。否则,您可以直接在迁移文件中手动指定表名。

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

可以使用存根发布来定制迁移存根。

挤压迁移

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

1php artisan schema:dump
2 
3# Dump the current database schema and prune all existing migrations...
4php artisan schema:dump --prune

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

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

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

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

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

移民结构

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

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

1<?php
2 
3use Illuminate\Database\Migrations\Migration;
4use Illuminate\Database\Schema\Blueprint;
5use Illuminate\Support\Facades\Schema;
6 
7return new class extends Migration
8{
9 /**
10 * Run the migrations.
11 */
12 public function up(): void
13 {
14 Schema::create('flights', function (Blueprint $table) {
15 $table->id();
16 $table->string('name');
17 $table->string('airline');
18 $table->timestamps();
19 });
20 }
21 
22 /**
23 * Reverse the migrations.
24 */
25 public function down(): void
26 {
27 Schema::drop('flights');
28 }
29};

设置迁移连接

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

1/**
2 * The database connection that should be used by the migration.
3 *
4 * @var string
5 */
6protected $connection = 'pgsql';
7 
8/**
9 * Run the migrations.
10 */
11public function up(): void
12{
13 // ...
14}

跳过迁移

有时,迁移可能需要支持尚未启用的功能,而您不希望它立即运行。在这种情况下,您可以shouldRun在迁移中定义一个方法。如果该shouldRun方法返回false,则迁移将被跳过:

1use App\Models\Flights;
2use Laravel\Pennant\Feature;
3 
4/**
5 * Determine if this migration should run.
6 */
7public function shouldRun(): bool
8{
9 return Feature::active(Flights::class);
10}

运行迁移

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

1php artisan migrate

如果您想查看迄今为止已运行的迁移,您可以使用migrate:statusArtisan 命令:

1php artisan migrate:status

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

1php artisan migrate --pretend

隔离迁移执行

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

当提供该isolated选项时,Laravel 将在尝试运行迁移之前使用应用程序的缓存驱动程序获取原子锁。migrate在持有该锁的情况下运行该命令的所有其他尝试都将无法执行;但是,该命令仍将以成功的退出状态码退出:

1php artisan migrate --isolated

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

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

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

1php artisan migrate --force

回滚迁移

要回滚最新的迁移操作,可以使用rollbackArtisan 命令。此命令会回滚上一“批”迁移,其中可能包含多个迁移文件:

1php artisan migrate:rollback

step您可以通过在命令中添加选项来回滚有限数量的迁移rollback。例如,以下命令将回滚最近的五次迁移:

1php artisan migrate:rollback --step=5

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

1php artisan migrate:rollback --batch=3

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

1php artisan migrate:rollback --pretend

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

1php artisan migrate:reset

使用单个命令回滚和迁移

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

1php artisan migrate:refresh
2 
3# Refresh the database and run all database seeds...
4php artisan migrate:refresh --seed

step您可以通过在命令中添加选项来回滚并重新迁移有限数量的迁移refresh。例如,以下命令将回滚并重新迁移最近的五个迁移:

1php artisan migrate:refresh --step=5

删除所有表并迁移

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

1php artisan migrate:fresh
2 
3php artisan migrate:fresh --seed

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

1php artisan migrate:fresh --database=admin

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

表格

创建表

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

1use Illuminate\Database\Schema\Blueprint;
2use Illuminate\Support\Facades\Schema;
3 
4Schema::create('users', function (Blueprint $table) {
5 $table->id();
6 $table->string('name');
7 $table->string('email');
8 $table->timestamps();
9});

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

确定表/列的存在

hasTable您可以使用、hasColumn和方法确定表、列或索引的存在hasIndex

1if (Schema::hasTable('users')) {
2 // The "users" table exists...
3}
4 
5if (Schema::hasColumn('users', 'email')) {
6 // The "users" table exists and has an "email" column...
7}
8 
9if (Schema::hasIndex('users', ['email'], 'unique')) {
10 // The "users" table exists and has a unique index on the "email" column...
11}

数据库连接和表选项

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

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

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

1Schema::create('users', function (Blueprint $table) {
2 $table->engine('InnoDB');
3 
4 // ...
5});

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

1Schema::create('users', function (Blueprint $table) {
2 $table->charset('utf8mb4');
3 $table->collation('utf8mb4_unicode_ci');
4 
5 // ...
6});

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

1Schema::create('calculations', function (Blueprint $table) {
2 $table->temporary();
3 
4 // ...
5});

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

1Schema::create('calculations', function (Blueprint $table) {
2 $table->comment('Business calculations');
3 
4 // ...
5});

更新表

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

1use Illuminate\Database\Schema\Blueprint;
2use Illuminate\Support\Facades\Schema;
3 
4Schema::table('users', function (Blueprint $table) {
5 $table->integer('votes');
6});

重命名/删除表

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

1use Illuminate\Support\Facades\Schema;
2 
3Schema::rename($from, $to);

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

1Schema::drop('users');
2 
3Schema::dropIfExists('users');

使用外键重命名表

在重命名表之前,你应该验证该表上的所有外键约束在迁移文件中都有明确的名称,而不是让 Laravel 分配一个约定俗成的名称。否则,外键约束名称将引用旧的表名。

创建列

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

1use Illuminate\Database\Schema\Blueprint;
2use Illuminate\Support\Facades\Schema;
3 
4Schema::table('users', function (Blueprint $table) {
5 $table->integer('votes');
6});

可用的列类型

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

布尔类型

字符串和文本类型

数字类型

日期和时间类型

二进制类型

对象和 Json 类型

UUID 和 ULID 类型

空间类型

关系类型

专业类型

bigIncrements()

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

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

bigInteger()

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

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

binary()

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

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

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

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

boolean()

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

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

char()

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

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

dateTimeTz()

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

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

dateTime()

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

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

date()

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

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

decimal()

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

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

double()

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

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

enum()

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

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

float()

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

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

foreignId()

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

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

foreignIdFor()

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

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

foreignUlid()

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

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

foreignUuid()

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

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

geography()

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

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

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

geometry()

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

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

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

id()

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

1$table->id();

increments()

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

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

integer()

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

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

ipAddress()

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

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

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

json()

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

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

当使用 SQLite 时,TEXT将会创建一个列。

jsonb()

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

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

当使用 SQLite 时,TEXT将会创建一个列。

longText()

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

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

当使用 MySQL 或 MariaDB 时,您可以将binary字符集应用于列以创建LONGBLOB等效列:

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

macAddress()

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

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

mediumIncrements()

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

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

mediumInteger()

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

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

mediumText()

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

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

当使用 MySQL 或 MariaDB 时,您可以将binary字符集应用于列以创建MEDIUMBLOB等效列:

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

morphs()

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

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

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

nullableMorphs()

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

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

nullableUlidMorphs()

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

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

nullableUuidMorphs()

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

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

rememberToken()

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

1$table->rememberToken();

set()

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

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

smallIncrements()

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

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

smallInteger()

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

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

softDeletesTz()

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

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

softDeletes()

softDeletes方法添加了一个可空的deleted_at TIMESTAMP等效列,其精度可选为秒的小数部分。此列用于存储deleted_atEloquent “软删除”功能所需的时间戳:

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

string()

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

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

text()

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

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

当使用 MySQL 或 MariaDB 时,您可以将binary字符集应用于列以创建BLOB等效列:

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

timeTz()

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

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

time()

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

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

timestampTz()

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

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

timestamp()

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

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

timestampsTz()

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

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

timestamps()

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

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

tinyIncrements()

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

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

tinyInteger()

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

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

tinyText()

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

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

当使用 MySQL 或 MariaDB 时,您可以将binary字符集应用于列以创建TINYBLOB等效列:

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

unsignedBigInteger()

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

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

unsignedInteger()

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

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

unsignedMediumInteger()

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

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

unsignedSmallInteger()

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

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

unsignedTinyInteger()

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

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

ulidMorphs()

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

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

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

uuidMorphs()

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

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

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

ulid()

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

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

uuid()

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

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

vector()

vector方法创建一个vector等效列:

1$table->vector('embedding', dimensions: 100);

year()

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

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

列修饰符

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

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

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

修饰符 描述
->after('column') 将列放置在另一列“之后”(MariaDB / MySQL)。
->autoIncrement() 将列设置INTEGER为自动递增(主键)。
->charset('utf8mb4') 为列指定字符集(MariaDB / MySQL)。
->collation('utf8mb4_unicode_ci') 指定列的排序规则。
->comment('my comment') 向列添加注释(MariaDB / MySQL / PostgreSQL)。
->default($value) 为该列指定“默认”值。
->first() 将列“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使用的列(MariaDB / MySQL)。CURRENT_TIMESTAMP
->virtualAs($expression) 创建一个虚拟生成的列(MariaDB / MySQL / SQLite)。
->generatedAs($expression) 创建具有指定序列选项的标识列(PostgreSQL)。
->always() 定义标识列(PostgreSQL)输入的序列值的优先级。

默认表达式

修饰符default可以接受一个值或一个Illuminate\Database\Query\Expression实例。使用Expression实例可以避免 Laravel 将值括在引号中,并允许你使用数据库特定的函数。当你需要为 JSON 列分配默认值时,这个修饰符会特别有用:

1<?php
2 
3use Illuminate\Support\Facades\Schema;
4use Illuminate\Database\Schema\Blueprint;
5use Illuminate\Database\Query\Expression;
6use Illuminate\Database\Migrations\Migration;
7 
8return new class extends Migration
9{
10 /**
11 * Run the migrations.
12 */
13 public function up(): void
14 {
15 Schema::create('flights', function (Blueprint $table) {
16 $table->id();
17 $table->json('movies')->default(new Expression('(JSON_ARRAY())'));
18 $table->timestamps();
19 });
20 }
21};

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

列顺序

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

1$table->after('password', function (Blueprint $table) {
2 $table->string('address_line1');
3 $table->string('address_line2');
4 $table->string('city');
5});

修改列

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

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

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

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

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

1// Add an index...
2$table->bigIncrements('id')->primary()->change();
3 
4// Drop an index...
5$table->char('postal_code', 10)->unique(false)->change();

重命名列

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

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

删除列

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

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

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

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

可用的命令别名

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

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

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

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

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

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

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

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

重命名索引

要重命名索引,可以使用renameIndexSchema Builder 蓝图提供的方法。该方法接受当前索引名称作为其第一个参数,并将所需的名称作为其第二个参数:

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

删除索引

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

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

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

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

外键约束

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

1use Illuminate\Database\Schema\Blueprint;
2use Illuminate\Support\Facades\Schema;
3 
4Schema::table('posts', function (Blueprint $table) {
5 $table->unsignedBigInteger('user_id');
6 
7 $table->foreign('user_id')->references('id')->on('users');
8});

由于此语法较为冗长,Laravel 提供了额外的、更简洁的方法,这些方法遵循约定,从而提供更佳的开发者体验。使用该foreignId方法创建列时,上述示例可以重写如下:

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

foreignId方法会创建一个UNSIGNED BIGINT等效的列,并根据constrained约定来确定引用的表和列。如果您的表名与 Laravel 的约定不符,您可以手动将其传递给该constrained方法。此外,还可以指定分配给生成索引的名称:

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

您还可以为约束的“删除时”和“更新时”属性指定所需的操作:

1$table->foreignId('user_id')
2 ->constrained()
3 ->onUpdate('cascade')
4 ->onDelete('cascade');

对于这些操作,还提供了一种替代的、富有表现力的语法:

方法 描述
$table->cascadeOnUpdate(); 更新应级联进行。
$table->restrictOnUpdate(); 更新应该受到限制。
$table->nullOnUpdate(); 更新应该将外键值设置为空。
$table->noActionOnUpdate(); 未对更新采取任何行动。
$table->cascadeOnDelete(); 删除应该级联。
$table->restrictOnDelete(); 删除应该受到限制。
$table->nullOnDelete(); 删除时应将外键值设置为空。
$table->noActionOnDelete(); 如果存在子记录,则防止删除。

任何附加的列修饰符都必须在该方法之前调用constrained

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

删除外键

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

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

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

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

切换外键约束

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

1Schema::enableForeignKeyConstraints();
2 
3Schema::disableForeignKeyConstraints();
4 
5Schema::withoutForeignKeyConstraints(function () {
6 // Constraints disabled within this closure...
7});

SQLite 默认禁用外键约束。使用 SQLite 时,请确保在迁移中创建外键之前,先在数据库配置中启用外键支持。

Events

为了方便起见,每个迁移操作都会调度一个事件。以下所有事件都扩展自基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 已加载现有的数据库架构转储。