迁移
简介
迁移就像是数据库的版本控制,它允许团队定义和共享应用程序的数据库模式定义。如果你曾经告诉队友在从源代码控制中拉取你的变更后,手动在本地数据库模式中添加一个列,那你就会面临数据库迁移解决的问题。
Laravel 的 Schema 门面提供了数据库无关的支持,用于在 Laravel 支持的所有数据库系统上创建和操作表。通常,迁移将使用此门面来创建和修改数据库表和列。
生成迁移
你可以使用 make:migration
Artisan 命令生成一个数据库迁移。新的迁移将放置在你的 database/migrations
目录中。每个迁移文件名都包含一个时间戳,用于 Laravel 确定迁移的顺序:
php artisan make:migration create_flights_table
Laravel 将使用迁移的名称来猜测表的名称以及迁移是否将创建新表。如果 Laravel 能够根据迁移名称确定表名,那么 Laravel 将在生成的迁移文件中预填充指定的表名。否则,你可以在迁移文件中手动指定表名。
如果你想为生成的迁移指定自定义路径,可以在执行 make:migration
命令时使用 --path
选项。给定的路径应相对于应用程序的基本路径。
迁移 stubs 可以使用 stub publishing 进行自定义。
合并迁移
随着应用程序的开发,可能会积累越来越多的迁移。这可能导致你的 database/migrations
目录中累积了数百个迁移。如果你希望,你可以将这些迁移“合并”为一个单独的 SQL 文件。要开始,请执行 schema:dump
命令:
php artisan schema:dump
# 导出当前数据库模式并清理所有现有的迁移...
php artisan schema:dump --prune
当你执行此命令时,Laravel 将在你的应用程序的 database/schema
目录中写入一个“schema”文件。模式文件名将对应于数据库连接。现在,当你尝试迁移数据库且没有其他迁移已经执行时,Laravel 将首先执行在所使用的数据库连接的模式文件中的 SQL 语句。在执行模式文件的 SQL 语句后,Laravel 将执行任何未包含在模式导出中的剩余迁移。
如果你的应用程序的测试使用的是与你在本地开发时使用的不同数据库连接,则应确保你已经使用该数据库连接导出了一个模式文件,以便你的测试能够构建你的数据库。你可能希望在导出本地开发时使用的数据库连接之后执行此操作:
php artisan schema:dump
php artisan schema:dump --database=testing --prune
你应该将你的数据库模式文件提交到源代码控制,以便团队中的新开发人员可以快速创建应用程序的初始数据库结构。
仅 MySQL、PostgreSQL 和 SQLite 数据库支持迁移合并,并且使用数据库的命令行客户端。模式导出文件不能还原到内存中的 SQLite 数据库。
迁移结构
迁移类包含两个方法:up
和 down
。up
方法用于向数据库添加新表、列或索引,而 down
方法应该撤销 up
方法所执行的操作。
在这两个方法中,你可以使用 Laravel schema builder 来表达地创建和修改表。要了解有关 Schema builder 上可用的所有方法,请查阅其文档。例如,以下迁移创建了一个 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::dropIfExists('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
隔离迁移执行
如果你将应用程序部署在多个服务器上,并且将迁移作为部署过程的一部分运行,你可能不希望两个服务器同时尝试对数据库进行迁移。为了避免这种情况,你可以在调用迁移命令时使用 isolated
选项。
当提供 isolated
选项时,Laravel 将在尝试运行迁移之前,使用应用程序的缓存驱动程序获取一个原子锁。当锁被保持时,所有其他尝试运行迁移的命令都不会执行;但是,命令将以成功的退出状态码退出:
php artisan migrate --isolated
要使用此功能,你的应用程序必须将
memcached
、redis
、dynamodb
、database
、file
或array
缓存驱动程序作为默认缓存驱动程序。此外,所有服务器都必须与相同的中央缓存服务器进行通信。
强制在生产环境下运行迁移
某些迁移操作可能是具有破坏性的,这意味着它们可能会导致数据丢失。为了保护你免受对生产数据库运行这些命令的影响,你将在执行命令之前被要求进行确认。如果要强制命令在没有提示的情况下运行,可以使用 --force
标志:
php artisan migrate --force
回滚迁移
要回滚最新的迁移操作,可以使用 rollback
Artisan 命令。此命令将回滚最后一个“批次”中的迁移,其中可能包含多个迁移文件:
php artisan migrate:rollback
可以通过向回滚命令提供 step
选项来回滚一定数量的迁移。例如,以下命令将回滚最后五个迁移:
php artisan migrate:rollback --step=5
可以通过向回滚命令提供 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
你可以通过向刷新命令提供 step
选项来回滚并重新执行一定数量的迁移。例如,以下命令将回滚并重新执行最后五个迁移:
php artisan migrate:refresh --step=5
删除所有表并迁移
migrate:fresh
命令将删除数据库中的所有表,然后执行 migrate
命令:
php artisan migrate:fresh
php artisan migrate:fresh --seed
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();
});
在创建表时,可以使用 schema
构建器的任意列方法来定义表的列。
检查表/列是否存在
可以使用 hasTable
和 hasColumn
方法检查表或列是否存在:
if (Schema::hasTable('users')) {
// "users" 表存在...
}
if (Schema::hasColumn('users', 'email')) {
// "users" 表存在,并且有一个 "email" 列...
}
数据库连接和表选项
如果你想在不是应用程序默认连接的数据库连接上执行模式操作,请使用 connection
方法:
Schema::connection('sqlite')->create('users', function (Blueprint $table) {
$table->id();
});
除此之外,还可以使用几个其他属性和方法来定义表的其他方面的选项。当使用 MySQL 时,可以使用 engine
属性来指定表的存储引擎:
Schema::create('users', function (Blueprint $table) {
$table->engine = 'InnoDB';
// ...
});
可以使用 charset
和 collation
属性来指定 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
方法。表注释目前仅支持 MySQL 和 Postgres:
Schema::create('calculations', function (Blueprint $table) {
$table->comment('Business calculations');
// ...
});
更新表
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');
});
重命名/删除表
要重命名现有的数据库表,可以使用 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');
});
可用的列类型
schema 构建器 blueprint 提供了一系列方法,对应于您可以添加到数据库表中的不同类型的列。可以在下表中找到所有可用方法:
bigIncrements
方法创建一个自增的无符号 BIGINT(主键)类型的列:
$table->bigIncrements('id');
bigInteger
方法创建一个 BIGINT 类型的列:
$table->bigInteger('votes');
binary
方法创建一个 BLOB 类型的列:
$table->binary('photo');
boolean
方法创建一个 BOOLEAN 类型的列:
$table->boolean('confirmed');
char
方法创建一个 CHAR 类型的列并指定长度:
$table->char('name', 100);
dateTimeTz
方法创建一个带时区的 DATETIME 类型的列,并可以指定精度(总位数):
$table->dateTimeTz('created_at', $precision = 0);
dateTime
方法创建一个 DATETIME 类型的列,并可以指定精度(总位数):
$table->dateTime('created_at', $precision = 0);
date
方法创建一个 DATE 类型的列:
$table->date('created_at');
decimal
方法创建一个 DECIMAL 类型的列,并可以指定精度(总位数)和小数位数:
$table->decimal('amount', $precision = 8, $scale = 2);
double
方法创建一个 DOUBLE 类型的列,并可以指定精度(总位数)和小数位数:
$table->double('amount', 8, 2);
enum
方法创建一个 ENUM 类型的列,并可以指定有效值:
$table->enum('difficulty', ['easy', 'hard']);
float
方法创建一个 FLOAT 类型的列,并可以指定精度(总位数)和小数位数:
$table->float('amount', 8, 2);
foreignId
方法创建一个 UNSIGNED BIGINT 类型的列:
$table->foreignId('user_id');
foreignIdFor
方法为给定的模型类添加一个 {column}_id
UNSIGNED BIGINT 类型的列:
$table->foreignIdFor(User::class);
foreignUlid
方法创建一个 ULID 类型的列:
$table->foreignUlid('user_id');
foreignUuid
方法创建一个 UUID 类型的列:
$table->foreignUuid('user_id');
geometryCollection
方法创建一个 GEOMETRYCOLLECTION 类型的列:
$table->geometryCollection('positions');
geometry
方法创建一个 GEOMETRY 类型的列:
$table->geometry('positions');
id
方法是 bigIncrements
方法的别名。默认情况下,此方法将创建 id
列;但是,如果要为列指定其他名称,可以传递一个列名:
$table->id();
increments
方法创建一个自增的 UNSIGNED INTEGER 类型的列作为主键:
$table->increments('id');
integer
方法创建一个 INTEGER 类型的列:
$table->integer('votes');
ipAddress
方法创建一个 VARCHAR 类型的列:
$table->ipAddress('visitor');
在使用 Postgres 时,将创建一个 INET 列。
json
方法创建一个 JSON 类型的列:
$table->json('options');
jsonb
方法创建一个 JSONB 类型的列:
$table->jsonb('options');
lineString
方法创建一个 LINESTRING 类型的列:
$table->lineString('positions');
longText
方法创建一个 LONGTEXT 类型的列:
$table->longText('description');
macAddress
方法创建一个用于存储 MAC 地址的列。某些数据库系统(如 PostgreSQL)有一个专用的列类型来存储此类型的数据。其他数据库系统将使用与字符串等效的列:
$table->macAddress('device');
mediumIncrements
方法创建一个自增的 UNSIGNED MEDIUMINT 类型的列作为主键:
$table->mediumIncrements('id');
mediumInteger
方法创建一个 MEDIUMINT 类型的列:
$table->mediumInteger('votes');
mediumText
方法创建一个 MEDIUMTEXT 类型的列:
$table->mediumText('description');
morphs
方法是一个方便的方法,它添加了一个 {column}_id
无符号大整型等价列和一个 {column}_type
字符串类型等价列。
这个方法的主要目的是在定义多态 Eloquent 关联所需的列时使用。在下面的示例中,将创建 taggable_id
和 taggable_type
两个列:
$table->morphs('taggable');
multiLineString
方法创建一个 MULTILINESTRING 类型的列:
$table->multiLineString('positions');
multiPoint
方法创建一个 MULTIPOINT 类型的列:
$table->multiPoint('positions');
multiPolygon
方法创建一个 MULTIPOLYGON 类型的列:
$table->multiPolygon('positions');
nullableMorphs
方法类似于 morphs
方法;但是,创建的列将为“nullable”:
$table->nullableMorphs('taggable');
nullableUlidMorphs
方法类似于 ulidMorphs
方法;但是,创建的列将为“nullable”:
$table->nullableUlidMorphs('taggable');
nullableUuidMorphs
方法类似于 uuidMorphs
方法;但是,创建的列将为“nullable”:
$table->nullableUuidMorphs('taggable');
point
方法创建一个 POINT 类型的列:
$table->point('position');
polygon
方法创建一个 POLYGON 类型的列:
$table->polygon('position');
rememberToken
方法创建一个可以存储当前“记住我”身份认证令牌(token)的可空 VARCHAR(100) 类型的列:
$table->rememberToken();
set
方法创建一个 SET 类型的列,并指定有效值的列表:
$table->set('flavors', ['strawberry', 'vanilla']);
smallIncrements
方法创建一个自增的 UNSIGNED SMALLINT 类型的列作为主键:
$table->smallIncrements('id');
smallInteger
方法创建一个 SMALLINT 类型的列:
$table->smallInteger('votes');
softDeletesTz
方法添加一个可空的 deleted_at
TIMESTAMP(带时区)类型的列,并可选地指定精度(总位数)。此列用于存储 Eloquent 的“软删除”功能所需的 deleted_at
时间戳:
$table->softDeletesTz($column = 'deleted_at', $precision = 0);
softDeletes
方法添加一个可空的 deleted_at
TIMESTAMP 类型的列,并可选地指定精度(总位数)。此列用于存储 Eloquent 的“软删除”功能所需的 deleted_at
时间戳:
$table->softDeletes($column = 'deleted_at', $precision = 0);
string
方法创建一个长度为给定长度的 VARCHAR 类型的列:
$table->string('name', 100);
text
方法创建一个 TEXT 类型的列:
$table->text('description');
timeTz
方法创建一个带时区的 TIME 类型的列,并可选地指定精度(总位数):
$table->timeTz('sunrise', $precision = 0);
time
方法创建一个 TIME 类型的列,并可选地指定精度(总位数):
$table->time('sunrise', $precision = 0);
timestampTz
方法创建一个带时区的 TIMESTAMP 类型的列,并可选地指定精度(总位数):
$table->timestampTz('added_at', $precision = 0);
timestamp
方法创建一个 TIMESTAMP 类型的列,并可选地指定精度(总位数):
$table->timestamp('added_at', $precision = 0);
timestampsTz
方法创建一个 created_at
和 updated_at
TIMESTAMP(带时区)类型的列,并可选地指定精度(总位数):
$table->timestampsTz($precision = 0);
timestamps
方法创建一个 created_at
和 updated_at
TIMESTAMP 类型的列,并可选地指定精度(总位数):
$table->timestamps($precision = 0);
tinyIncrements
方法创建一个自增的 UNSIGNED TINYINT 类型的列作为主键:
$table->tinyIncrements('id');
tinyInteger
方法创建一个 TINYINT 类型的列:
$table->tinyInteger('votes');
tinyText
方法创建一个 TINYTEXT 类型的列:
$table->tinyText('notes');
unsignedBigInteger
方法创建一个 UNSIGNED BIGINT 类型的列:
$table->unsignedBigInteger('votes');
unsignedDecimal
方法创建一个 UNSIGNED DECIMAL 类型的列,并可选地指定精度(总位数)和小数位数:
$table->unsignedDecimal('amount', $precision = 8, $scale = 2);
unsignedInteger
方法创建一个 UNSIGNED INTEGER 类型的列:
$table->unsignedInteger('votes');
unsignedMediumInteger
方法创建一个 UNSIGNED MEDIUMINT 类型的列:
$table->unsignedMediumInteger('votes');
unsignedSmallInteger
方法创建一个 UNSIGNED SMALLINT 类型的列:
$table->unsignedSmallInteger('votes');
unsignedTinyInteger
方法创建一个 UNSIGNED TINYINT 类型的列:
$table->unsignedTinyInteger('votes');
ulidMorphs
方法是 morphs
方法的一个方便方法,它添加了一个 {column}_id
CHAR(26) 类型的列和一个 {column}_type
VARCHAR 类型的列。它用于在定义多态 Eloquent 关系所需的列。在下面的示例中,将创建 taggable_id
和 taggable_type
列:
$table->ulidMorphs('taggable');
uuidMorphs
方法是 morphs
方法的一个方便方法,它添加了一个 {column}_id
CHAR(36) 类型的列和一个 {column}_type
VARCHAR 类型的列。它用于在定义多态 Eloquent 关系所需的列。在下面的示例中,将创建 taggable_id
和 taggable_type
列:
$table->uuidMorphs('taggable');
ulid
方法创建一个 ULID 类型的列:
$table->ulid('id');
uuid
方法创建一个 UUID 类型的列:
$table->uuid('id');
**year()
**
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();
});
以下表格包含了所有可用的列修饰符。此列表不包括索引修饰符:
下面是您所要求的Markdown表格:
修饰符 | 描述 |
---|---|
->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(MySQL)。 |
->virtualAs($expression) |
创建一个虚拟生成的列(MySQL)。 |
->generatedAs($expression) |
创建一个具有指定序列选项的自增列(PostgreSQL)。 |
->always() |
定义序列值在输入上的优先级,而不是在标识列上(PostgreSQL)。 |
->isGeometry() |
将空间列类型设置为 geometry - 默认类型为 geography (PostgreSQL)。 |
默认表达式
default
修饰符接受一个值或一个 Illuminate\Database\Query\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();
});
}
};
默认表达式的支持取决于您的数据库驱动程序、数据库版本和字段类型。请参阅数据库的文档。
列顺序
在使用 MySQL 数据库时,可以使用 after
方法将列添加到模式中的现有列后面:
$table->after('password', function (Blueprint $table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});
修改列
change
方法允许你修改现有列的类型和属性。例如,你可能希望增加一个字符串列的大小。为了演示 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();
});
在 SQLite 上修改列
如果你的应用程序使用 SQLite 数据库,在修改列之前,你必须使用 Composer 包管理器安装 doctrine/dbal
软件包。Doctrine DBAL 库用于确定列的当前状态,并创建需要对列进行请求的更改的 SQL 查询:
composer require doctrine/dbal
如果计划修改使用 timestamp
方法创建的列,还必须将以下配置添加到应用程序的 config/database.php
配置文件中:
use Illuminate\Database\DBAL\TimestampType;
'dbal' => [
'types' => [
'timestamp' => TimestampType::class,
],
],
在使用
doctrine/dbal
软件包时,可以修改以下列类型:bigInteger
、binary
、boolean
、char
、date
、dateTime
、dateTimeTz
、decimal
、double
、integer
、json
、longText
、mediumText
、smallInteger
、string
、text
、time
、tinyText
、unsignedBigInteger
、unsignedInteger
、unsignedSmallInteger
、ulid
和uuid
。
重命名列
要重命名列,可以使用 schema builder 提供的 renameColumn
方法:
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
删除列
要删除列,可以使用 schema builder 的 dropColumn
方法:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});
可以通过将列名称的数组传递给 dropColumn
方法来从表中删除多个列:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});
在传统数据库上删除列
如果你运行的是 SQLite 3.35.0 之前的版本,必须使用 Composer 包管理器安装 doctrine/dbal
库,然后才能使用 dropColumn
方法。不支持在使用该软件包时一次性删除或修改多个列。
可用的命令别名
Laravel提供了几个方便的方法用于删除常见类型的列。下表描述了每个方法:
命令 | 描述 |
---|---|
$table->dropMorphs('morphable'); |
删除 morphable_id 和 morphable_type 两列。 |
$table->dropRememberToken(); |
删除 remember_token 列。 |
$table->dropSoftDeletes(); |
删除 deleted_at 列。 |
$table->dropSoftDeletesTz(); |
dropSoftDeletes() 方法的别名。 |
$table->dropTimestamps(); |
删除 created_at 和 updated_at 两列。 |
$table->dropTimestampsTz(); |
dropTimestamps() 方法的别名。 |
索引
创建索引
Laravel schema builder 支持多种类型的索引。下面的示例创建一个新的 email
列,并指定其值应该是唯一的。为了创建索引,我们可以在列定义上链接 unique
方法:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});
或者,你可以在定义列之后创建索引。为此,你应该在 schema builder 蓝图上调用 unique
方法。此方法接受应接收唯一索引的列的名称:
$table->unique('email');
你甚至可以将一个列名的数组传递给 index
方法,以创建一个复合索引(或组合索引):
$table->index(['account_id', 'created_at']);
创建索引时,Laravel 将根据表名、列名和索引类型自动生成索引名称,但是你可以传递第二个参数来指定索引名称:
$table->unique('email', 'unique_email');
可用的索引类型
Laravel 的 schema builder blueprint 类提供了创建 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 版本,为了让 MySQL 为迁移生成的字符串创建索引,你可能需要手动配置默认的字符串长度。你可以在 App\Providers\AppServiceProvider
类的 boot
方法中调用 Schema::defaultStringLength
方法来配置默认的字符串长度:
use Illuminate\Support\Facades\Schema;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Schema::defaultStringLength(191);
}
或者,你可以为数据库启用 innodb_large_prefix
选项。有关如何正确启用此选项的说明,请参阅数据库的文档。
重命名索引
要重命名索引,可以使用 schema builder 蓝图提供的 renameIndex
方法。该方法接受当前索引名称作为第一个参数,所需名称作为第二个参数:
$table->renameIndex('from', 'to')
如果你的应用程序使用 SQLite 数据库,在使用
renameIndex
方法之前,你必须通过 Composer 包管理器安装doctrine/dbal
包。
删除索引
要删除索引,必须指定索引的名称。默认情况下,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->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 时,请确保在尝试在迁移中创建外键之前,在数据库配置中启用外键支持。此外,在创建表时,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 |
已加载现有数据库模式转储。 |
No Comments