跳到内容

数据库:迁移

简介

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

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

生成迁移

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

1php artisan make:migration create_flights_table

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

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

迁移桩可以 使用 桩发布 进行自定义。

压缩迁移

随着你构建应用程序,随着时间的推移,你可能会积累越来越多的迁移。这可能会导致你的 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 会将“模式”文件写入到你的应用程序的 database/schema 目录中。模式文件的名称将与数据库连接相对应。现在,当你尝试迁移数据库并且没有其他迁移被执行时,Laravel 将首先执行你正在使用的数据库连接的模式文件中的 SQL 语句。在执行模式文件的 SQL 语句后,Laravel 将执行任何未包含在模式转储中的剩余迁移。

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

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}

运行迁移

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

1php artisan migrate

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

1php artisan migrate:status

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

1php artisan migrate --pretend

隔离迁移执行

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

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

1php artisan migrate --isolated

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

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

一些迁移操作是破坏性的,这意味着它们可能会导致你丢失数据。为了保护你免受针对你的生产数据库运行这些命令的影响,在执行命令之前,系统会提示你进行确认。要强制命令在没有提示的情况下运行,请使用 --force 标志。

1php artisan migrate --force

回滚迁移

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

1php artisan migrate:rollback

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

1php artisan migrate:rollback --step=5

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

1php artisan migrate:rollback --batch=3

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

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

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

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 命令都将删除所有数据库表。当在与其他应用程序共享的数据库上进行开发时,应谨慎使用此命令。

数据表

创建数据表

要创建新的数据库表,请使用 Schema facade 上的 create 方法。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});

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

确定表/列是否存在

你可以使用 hasTablehasColumnhasIndex 方法来确定表、列或索引是否存在。

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

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

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

更新数据表

Schema facade 上的 table 方法可用于更新现有表。与 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 分配基于约定的名称。否则,外键约束名称将引用旧表名。

创建列

Schema facade 上的 table 方法可用于更新现有表。与 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 方法创建一个具有给定空间类型和 SRID(空间参考系统标识符)的 GEOGRAPHY 等效列。

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

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

geometry()

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

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

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

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}_id 的列类型将是 UNSIGNED BIGINTCHAR(36)CHAR(26),具体取决于模型键类型。

此方法旨在用于定义多态 Eloquent 关系所需的列。在以下示例中,将创建 taggable_idtaggable_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 (带时区) 等效列,并具有可选的秒后小数精度。此列旨在存储 Eloquent 的“软删除”功能所需的 deleted_at 时间戳。

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

softDeletes()

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

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_atupdated_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_idtaggable_type 列。

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

uuidMorphs()

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

此方法旨在用于定义使用 UUID 标识符的多态 Eloquent 关系所需的列。在以下示例中,将创建 taggable_idtaggable_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() 将列放在表的“第一”位置 (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 列分配默认值时

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

重命名索引

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

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

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

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

外键约束

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

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

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

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 时,请确保在尝试在迁移中创建它们之前,在您的数据库配置中 启用外键支持

事件

为了方便起见,每个迁移操作都将分派一个 事件。以下所有事件都扩展了基类 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 现有的数据库模式转储已加载。

Laravel 是最有效率的方式来
构建、部署和监控软件。