迁移就像用于您的数据库的版本控制,允许您的团队定义和共享应用程序的数据库模式定义。如果您曾不得不告诉队友在从源代码管理拉取您的更改之后手动添加一个列到他们的本地数据库模式中,您就遇到了数据库迁移所解决的问题。
Laravel 的 Schema 门面 提供了数据库无关的支持用于跨所有 Laravel 支持的数据库系统创建和操作表。通常,迁移会使用此门面来创建和修改数据库表和列。
您可以使用 make:migration Artisan 命令 来生成数据库迁移。新的迁移文件将放在您的 database/migrations 目录中。每个迁移文件名都包含一个时间戳,允许 Laravel 确定迁移的顺序:
php artisan make:migration create_flights_tableLaravel 将使用迁移的名称来尝试猜测表的名称,以及该迁移是否将创建新表。如果 Laravel 能够从迁移名称中确定表名,Laravel 将使用指定的表预填充生成的迁移文件。否则,您可以简单地在迁移文件中手动指定表。
如果您想为生成的迁移指定自定义路径,您可以在执行 make:migration 命令时使用 --path 选项。给定的路径应相对于您的应用程序的基础路径。
[!NOTE]
迁移存根可以使用存根发布进行自定义.
随着应用程序的开发,你可能会逐渐积累越来越多的迁移。这可能导致你的 database/migrations 目录变得臃肿,可能包含数百个迁移。如果你愿意,你可以将你的迁移“合并”到一个单独的 SQL 文件中。要开始,请执行 schema:dump 命令:
php artisan schema:dump
# Dump the current database schema and prune all existing migrations...
php artisan schema:dump --prune当你执行此命令时,Laravel 会将一个“模式”文件写入到你应用程序的 database/schema 目录。该模式文件的名称将与数据库连接对应。现在,当你尝试迁移数据库并且没有其他迁移被执行过时,Laravel 将首先执行你正在使用的数据库连接的模式文件中的 SQL 语句。在执行完模式文件的 SQL 语句后,Laravel 将会执行任何不属于模式转储的剩余迁移。
如果您的应用程序的测试使用的数据库连接与您在本地开发期间通常使用的不同,您应该确保您已经使用该数据库连接转储了模式文件,以便您的测试能够构建您的数据库。您可能希望在转储了您在本地开发期间通常使用的数据库连接之后执行此操作:
php artisan schema:dump
php artisan schema:dump --database=testing --prune你应该将你的数据库架构文件提交到源代码管理,以便你的团队中的其他新开发人员能够快速创建你的应用程序的初始数据库结构。
[!WARNING]
迁移压缩仅适用于 MariaDB、MySQL、PostgreSQL 和 SQLite 数据库,并利用该数据库的命令行客户端。
A migration class contains two methods: up and down. The up method is used to add new tables, columns, or indexes to your database, while the down method should reverse the operations performed by the up method.
在这两种方法中,你都可以使用 Laravel 架构构建器来富有表现力地创建和修改表。要了解 Schema 构建器上所有可用的方法,请查阅其文档。例如,以下迁移会创建一个 flights 表:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::drop('flights');
}
};如果您的迁移将与一个不同于您的应用程序默认数据库连接的数据库连接交互,您应该设置您的迁移的$connection属性:
/**
* The database connection that should be used by the migration.
*
* @var string
*/
protected $connection = 'pgsql';
/**
* Run the migrations.
*/
public function up(): void
{
// ...
}有时,迁移可能旨在支持一个尚未激活的功能,并且你不想让它现在就运行。在这种情况下,你可以在迁移上定义一个 shouldRun 方法。如果 shouldRun 方法返回 false,该迁移将被跳过:
use App\Models\Flights;
use Laravel\Pennant\Feature;
/**
* Determine if this migration should run.
*/
public function shouldRun(): bool
{
return Feature::active(Flights::class);
}要运行所有待处理的迁移,执行 migrate Artisan 命令:
php artisan migrate如果您想查看哪些迁移已运行以及哪些仍在等待,您可以使用 migrate:status Artisan 命令:
php artisan migrate:status如果您想查看将由迁移执行的 SQL 语句,而不实际运行它们,您可以将 --pretend 标志提供给 migrate 命令:
php artisan migrate --pretend如果您正在跨多个服务器部署您的应用程序,并且将数据库迁移作为部署过程的一部分来运行,您可能不希望两个服务器同时尝试迁移数据库。为避免这种情况,您可以在调用 migrate 命令时使用 isolated 选项。
当提供 isolated 选项时,在尝试运行您的迁移之前,Laravel 将使用您的应用程序的缓存驱动程序获取一个原子锁。在该锁被持有期间,所有其他尝试运行 migrate 命令的操作都不会执行;然而,该命令仍将以成功的退出状态码退出:
php artisan migrate --isolated[!WARNING]
要使用此功能,您的应用程序必须使用memcached、redis、dynamodb、database、file或array缓存驱动程序作为您应用程序的默认缓存驱动程序。此外,所有服务器必须与同一个中心缓存服务器通信。
某些迁移操作是破坏性的,这意味着它们可能会导致您丢失数据。为了保护您避免在生产数据库上运行这些命令,在命令执行之前会提示您进行确认。要强制命令在没有提示的情况下运行,请使用 --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 --pretendmigrate:reset 命令将回滚你的应用程序的所有迁移:
php artisan migrate:reset这个 migrate:refresh 命令将回滚所有迁移,然后执行 migrate 命令。这个命令会有效地重新创建你的整个数据库:
php artisan migrate:refresh
# Refresh the database and run all database seeds...
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
[!WARNING]
migrate:fresh命令将会删除所有数据库表,无论它们是否有前缀。当在与其他应用程序共享的数据库上进行开发时,应谨慎使用此命令。
要创建新的数据库表,请使用 Schema facade 上的 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();
});创建表时,您可以使用任何架构构建器的列方法来定义表的列。
您可以使用 hasTable、hasColumn 和 hasIndex 方法确定表、列或索引的存在:
if (Schema::hasTable('users')) {
// The "users" table exists...
}
if (Schema::hasColumn('users', 'email')) {
// The "users" table exists and has an "email" column...
}
if (Schema::hasIndex('users', ['email'], 'unique')) {
// The "users" table exists and has a unique index on the "email" column...
}如果您想在非应用程序默认的数据库连接上执行结构操作,请使用 connection 方法:
Schema::connection('sqlite')->create('users', function (Blueprint $table) {
$table->id();
});此外,还有一些其他属性和方法可用于定义表创建的其他方面。engine 属性可用于在使用 MariaDB 或 MySQL 时指定表的存储引擎:
Schema::create('users', function (Blueprint $table) {
$table->engine('InnoDB');
// ...
});The charset and collation properties may be used to specify the character set and collation for the created table when using MariaDB or MySQL:
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, and 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);要删除现有表,您可以使用 drop 或 dropIfExists 方法:
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');
});架构构建器蓝图提供了多种方法,这些方法对应于可以添加到数据库表的不同类型的列。每种可用方法都列在下表中:
char
longText
mediumText
string
text
tinyText
bigIncrements
bigInteger
decimal
double
float
id
increments
integer
mediumIncrements
mediumInteger
smallIncrements
smallInteger
tinyIncrements
tinyInteger
unsignedBigInteger
unsignedInteger
unsignedMediumInteger
unsignedSmallInteger
unsignedTinyInteger
dateTime
dateTimeTz
date
time
timeTz
timestamp
timestamps
timestampsTz
softDeletes
softDeletesTz
year
ulid
ulidMorphs
uuid
uuidMorphs
nullableUlidMorphs
nullableUuidMorphs
foreignId
foreignIdFor
foreignUlid
foreignUuid
morphs
nullableMorphs
enum
set
macAddress
ipAddress
rememberToken
vector
bigIncrements()该 bigIncrements 方法创建一个自增的 UNSIGNED BIGINT (主键) 等效列:
$table->bigIncrements('id');bigInteger()bigInteger 方法创建一个等效于 BIGINT 的列:
$table->bigInteger('votes');binary()该 binary 方法创建一个 BLOB 等效列:
$table->binary('photo');当使用 MySQL、MariaDB 或 SQL Server 时,您可以传递 length 和 fixed 参数以创建 VARBINARY 或 BINARY 等效列:
$table->binary('data', length: 16); // VARBINARY(16)
$table->binary('data', length: 16, fixed: true); // BINARY(16)布尔()boolean 方法会创建一个 BOOLEAN 等价的列:
$table->boolean('confirmed');字符()该 char 方法创建一个 CHAR 等效列,具有给定长度:
$table->char('name', length: 100);dateTimeTz()该 dateTimeTz 方法 创建 一个 DATETIME (带有时区) 等效 列 具有 一个 可选的 小数 秒 精度:
$table->dateTimeTz('created_at', precision: 0);dateTime()dateTime 方法创建一个 DATETIME 等效列,具有可选的小数秒精度:
$table->dateTime('created_at', precision: 0);日期()date 方法创建一个 DATE 等效列:
$table->date('created_at');decimal()该 decimal 方法创建一个 DECIMAL 等效列,具有给定的精度(总位数)和小数位数(小数位数):
$table->decimal('amount', total: 8, places: 2);double()该 double 方法创建了一个 DOUBLE 等效列:
$table->double('amount');enum()该 enum 方法 创建 一个 ENUM 等效 列 使用 其 给定 有效 值:
$table->enum('difficulty', ['easy', 'hard']);当然,您可以使用 Enum::cases() 方法,而不是手动定义允许值的数组:
use App\Enums\Difficulty;
$table->enum('difficulty', Difficulty::cases());float()float 方法创建一个 FLOAT 等效列,并具有给定精度:
$table->float('amount', precision: 53);foreignId()foreignId方法创建一个UNSIGNED BIGINT等效列:
$table->foreignId('user_id');foreignIdFor()该 foreignIdFor 方法添加一个 {column}_id 等效列用于给定模型类。该列类型将是 UNSIGNED BIGINT, CHAR(36), 或 CHAR(26) 依据模型键类型:
$table->foreignIdFor(User::class);外键 ULID()该 foreignUlid 方法创建一个等效于 ULID 的列:
$table->foreignUlid('user_id');foreignUuid()该 foreignUuid 方法创建了一个 UUID 等效的列:
$table->foreignUuid('user_id');geography()geography 方法创建一个等效的 GEOGRAPHY 列,具有给定的空间类型和 SRID(空间参考系统标识符):
$table->geography('coordinates', subtype: 'point', srid: 4326);[!NOTE]
空间类型的支持取决于您的数据库驱动。请参考您的数据库文档。如果您的应用程序正在使用 PostgreSQL 数据库,您必须安装 PostGIS 扩展,然后才能使用geography方法。
geometry()该 geometry 方法创建一个 GEOMETRY 等效列,具有给定的空间类型和 SRID(空间参考系统标识符):
$table->geometry('positions', subtype: 'point', srid: 0);[!NOTE]
对空间类型的支持取决于您的数据库驱动程序。请参考您的数据库文档。如果您的应用程序正在使用 PostgreSQL 数据库,您必须安装 PostGIS 扩展,然后才能使用geometry方法。
id()id 方法是 bigIncrements 方法的别名。默认情况下,该方法将创建一个 id 列;但是,如果您想为该列指定一个不同的名称,您可以传递一个列名:
$table->id();increments()该 increments 方法创建一个自增的 UNSIGNED INTEGER 等效列作为主键:
$table->increments('id');整数()该 integer 方法创建一个 INTEGER 等效列:
$table->integer('votes');ipAddress()ipAddress 方法创建一个 VARCHAR 等效列:
$table->ipAddress('visitor');使用 PostgreSQL 时,将创建一个 INET 列。
json()该 json 方法 创建 一个 JSON 等效的 列:
$table->json('options');当使用 SQLite 时, 一个 TEXT 列将被创建.
jsonb()这个 jsonb 方法创建一个 JSONB 等效列:
$table->jsonb('options');当使用 SQLite 时, 一个 TEXT 列将被创建。
longText()该 longText 方法创建一个 LONGTEXT 等效列:
$table->longText('description');当使用 MySQL 或 MariaDB 时,您可以将 binary 字符集应用到该列,以创建 LONGBLOB 等效列:
$table->longText('data')->charset('binary'); // LONGBLOBmacAddress()该 macAddress 方法创建了一个旨在用于存储 MAC 地址的列。一些数据库系统,例如 PostgreSQL,为此类数据提供了专用的列类型。其他数据库系统将使用等效的字符串列:
$table->macAddress('device');mediumIncrements()这个 mediumIncrements 方法创建一个自增的 UNSIGNED MEDIUMINT 等效列作为主键:
$table->mediumIncrements('id');mediumInteger()mediumInteger 方法会创建一个 MEDIUMINT 等效的列:
$table->mediumInteger('votes');mediumText()该 mediumText 方法创建一个 MEDIUMTEXT 等效的列:
$table->mediumText('description');当使用 MySQL 或 MariaDB 时,您可以将 binary 字符集应用于该列,以创建等效于 MEDIUMBLOB 的列:
$table->mediumText('data')->charset('binary'); // MEDIUMBLOBmorphs()morphs 方法是一个便捷方法,用于添加一个 {column}_id 等效列和一个 {column}_type VARCHAR 等效列。{column}_id 的列类型将是 UNSIGNED BIGINT、CHAR(36) 或 CHAR(26),具体取决于模型键的类型。
此方法旨在用于定义多态 Eloquent 关联所需的字段。在以下示例中,将创建 taggable_id 和 taggable_type 字段:
$table->morphs('taggable');nullableMorphs()该方法类似于 morphs 方法; 但是, 创建的列将是"可为空的":
$table->nullableMorphs('taggable');可空ULID多态关联()该方法类似于 ulidMorphs 方法;然而,创建的列将是“可为空的”:
$table->nullableUlidMorphs('taggable');nullableUuidMorphs()该方法类似于 uuidMorphs 方法;然而,创建的列将是“可空”的:
$table->nullableUuidMorphs('taggable');rememberToken()该 rememberToken 方法会创建一个可空, 等效于 VARCHAR(100) 的列, 该列用于存储当前的“记住我”认证令牌:
$table->rememberToken();set()set 方法创建一个 SET 等效列,该列包含给定有效值列表:
$table->set('flavors', ['strawberry', 'vanilla']);smallIncrements()该 smallIncrements 方法创建一个自增的 UNSIGNED SMALLINT 等效列作为主键:
$table->smallIncrements('id');smallInteger()该 smallInteger 方法 创建了一个 SMALLINT 等效的 列:
$table->smallInteger('votes');softDeletesTz()softDeletesTz 方法添加一个可空的 deleted_at TIMESTAMP(带时区)等效列,具有可选的秒级精度。该列旨在存储 Eloquent 的“软删除”功能所需的 deleted_at 时间戳:
$table->softDeletesTz('deleted_at', precision: 0);softDeletes()softDeletes 方法添加一个可为空的 deleted_at TIMESTAMP 等效列,具有可选的毫秒精度。此列旨在存储 Eloquent 的“软删除”功能所需的 deleted_at 时间戳:
$table->softDeletes('deleted_at', precision: 0);string()该 string 方法 创建 一个 VARCHAR 等效 列 的 该 给定 长度:
$table->string('name', length: 100);文本()text 方法创建了一个 TEXT 等效的列:
$table->text('description');当使用 MySQL 或 MariaDB, 您可以对列应用 binary 字符集以创建 BLOB 等效列:
$table->text('data')->charset('binary'); // BLOBtimeTz()该 timeTz 方法创建了一个 TIME (带有时区)等效列,具有可选的小数秒精度:
$table->timeTz('sunrise', precision: 0);time()time 方法创建一个等效于 TIME 的列,具有可选的秒小数精度:
$table->time('sunrise', precision: 0);timestampTz()timestampTz 方法创建 TIMESTAMP (带时区) 等效列,具有可选的秒级小数精度:
$table->timestampTz('added_at', precision: 0);timestamp()这 timestamp 方法 创建一个 TIMESTAMP 等效列,具有 可选的 小数秒精度:
$table->timestamp('added_at', precision: 0);timestampsTz()该 timestampsTz 方法创建 created_at 和 updated_at TIMESTAMP (带时区)等效列,具有可选的小数秒精度:
$table->timestampsTz(precision: 0);时间戳()timestamps 方法会创建 created_at 和 updated_at 这两个 TIMESTAMP 等效列,并支持可选的小数秒精度:
$table->timestamps(precision: 0);tinyIncrements()tinyIncrements 方法创建一个自增的 UNSIGNED TINYINT 等效列作为主键:
$table->tinyIncrements('id');tinyInteger()tinyInteger 方法创建一个 TINYINT 等效的列:
$table->tinyInteger('votes');tinyText()tinyText 方法会创建一个 TINYTEXT 等效列:
$table->tinyText('notes');当使用 MySQL 或 MariaDB 时,您可以应用一个 binary 字符集到该列,以创建一个 TINYBLOB 等效列:
$table->tinyText('data')->charset('binary'); // TINYBLOB无符号大整数() ``unsignedBigInteger 方法创建了一个 UNSIGNED BIGINT 等效列:
$table->unsignedBigInteger('votes');unsignedInteger()这个 unsignedInteger 方法创建一个 UNSIGNED INTEGER 等效列:
$table->unsignedInteger('votes');unsignedMediumInteger()unsignedMediumInteger 方法创建一个等价于 UNSIGNED MEDIUMINT 的列:
$table->unsignedMediumInteger('votes');无符号小整数()unsignedSmallInteger 方法创建了一个等同于 UNSIGNED SMALLINT 的列:
$table->unsignedSmallInteger('votes');无符号迷你整型()unsignedTinyInteger 方法创建一个等效的 UNSIGNED TINYINT 列:
$table->unsignedTinyInteger('votes');ulidMorphs()ulidMorphs 方法是一个便利方法,用于添加一个 {column}_id CHAR(26) 等效列和一个 {column}_type VARCHAR 等效列。
此方法旨在用于定义使用 ULID 标识符的多态 Eloquent 关联 所需的列。在以下示例中,将创建 taggable_id 和 taggable_type 列:
$table->ulidMorphs('taggable');uuidMorphs()该 uuidMorphs 方法是一个便利方法 用于 添加 一个 {column}_id CHAR(36) 等效列 和 一个 {column}_type VARCHAR 等效列。
此方法旨在用于定义多态 Eloquent 关系 所需的列,该关系使用 UUID 标识符。在以下示例中,taggable_id 和 taggable_type 列将会被创建:
$table->uuidMorphs('taggable');ulid()ulid 方法创建一个 ULID 等效列:
$table->ulid('id');uuid()该 uuid 方法创建一个 UUID 等效的列:
$table->uuid('id');vector()该 vector 方法创建了一个 vector 等效列:
$table->vector('embedding', dimensions: 100);年()该 year 方法创建一个 YEAR 等效列:
$table->year('birth_year');除了上述列出的列类型之外,在向数据库表添加列时,还可以使用几个列“修饰符”。例如,要使该列“可为空”,你可以使用 nullable 方法:
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
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
{
/**
* Run the migrations.
*/
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 方法可用于在模式中现有列之后添加列:
$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();
});在修改列时,您必须在列定义中显式包含所有希望保留的修饰符——任何未包含的属性都会被移除。例如,如果要保留 unsigned、default 和 comment 属性,则在修改该列时必须显式调用每个修饰符:
Schema::table('users', function (Blueprint $table) {
$table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
});change 方法不会更改列的索引。 因此,您可以使用索引修饰符在修改列时显式地添加或删除索引:
// Add an index...
$table->bigIncrements('id')->primary()->change();
// Drop an index...
$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 提供了多种便捷方法,用于删除常见类型的列。每种方法都将在下表中进行描述:
| Command | Description |
|---|---|
$table->dropMorphs('morphable'); | Drop the morphable_id and morphable_type columns. |
$table->dropRememberToken(); | Drop the remember_token column. |
$table->dropSoftDeletes(); | Drop the deleted_at column. |
$table->dropSoftDeletesTz(); | Alias of dropSoftDeletes() method. |
$table->dropTimestamps(); | Drop the created_at and updated_at columns. |
$table->dropTimestampsTz(); | Alias of dropTimestamps() method. |
Laravel 模式构建器支持多种索引类型。以下示例创建一个新的 email 列并指定其值应唯一。要创建此索引,我们可以将 unique 方法链式调用到列定义上:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});或者,你可以在定义列之后创建索引。为此,你应该调用 schema builder blueprint 上的 unique 方法。此方法接受将接收唯一索引的列名:
$table->unique('email');你甚至可以传递一个列数组到一个索引方法来创建一个复合(或组合)索引:
$table->index(['account_id', 'created_at']);当创建索引时,Laravel 将自动根据表、列名和索引类型生成索引名称,但你可以向该方法传递第二个参数来自定义索引名称:
$table->unique('email', 'unique_email');Laravel 的模式构建器蓝图类提供了用于创建 Laravel 支持的每种索引类型的方法。每个索引方法都接受一个可选的第二个参数,用于指定索引的名称。如果省略,索引名称将从用于索引的表和列的名称以及索引类型中派生出来。每个可用的索引方法都在下表中描述:
| Command | Description |
|---|---|
$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']); // Drops index '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->nullOnUpdate(); | 更新时将外键值设置为 null。 |
$table->noActionOnUpdate(); | 更新时不执行任何操作。 |
$table->cascadeOnDelete(); | 删除时进行级联操作。 |
$table->restrictOnDelete(); | 删除时进行限制操作。 |
$table->nullOnDelete(); | 删除时将外键值设置为 null。 |
$table->noActionOnDelete(); | 如果存在子记录,则阻止删除操作。 |
任何额外的列修饰符必须在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 () {
// Constraints disabled within this closure...
});[!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 | 现有的数据库架构导入已完成。 |