数据库:迁移
介绍
迁移就像数据库的版本控制,允许你的团队定义和共享应用程序的数据库模式。如果你曾经在从源代码控制中提取更改后,不得不告诉队友手动向其本地数据库模式添加一列,那么你遇到的问题正是数据库迁移可以解决的。
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:dump2 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:dump2php artisan schema:dump --database=testing --prune
您应该将数据库模式文件提交到源代码控制,以便团队中的其他新开发人员可以快速创建应用程序的初始数据库结构。
迁移压缩仅适用于 MariaDB、MySQL、PostgreSQL 和 SQLite 数据库,并利用数据库的命令行客户端。
移民结构
迁移类包含两个方法:up
和down
。up
方法用于向数据库添加新表、列或索引,而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(): void13 {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(): void26 {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(): void12{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}
运行迁移
要运行所有未完成的迁移,请执行migrate
Artisan 命令:
1php artisan migrate
如果您想查看迄今为止已运行的迁移,您可以使用migrate:status
Artisan 命令:
1php artisan migrate:status
如果您希望查看迁移将执行的 SQL 语句而不实际运行它们,您可以--pretend
为migrate
命令提供标志:
1php artisan migrate --pretend
隔离迁移执行
如果您正在跨多台服务器部署应用程序,并在部署过程中运行迁移,您可能不希望两台服务器同时尝试迁移数据库。为了避免这种情况,您可以isolated
在调用migrate
命令时使用该选项。
当提供该isolated
选项时,Laravel 将在尝试运行迁移之前使用应用程序的缓存驱动程序获取原子锁。migrate
在持有该锁的情况下运行该命令的所有其他尝试都将无法执行;但是,该命令仍将以成功的退出状态码退出:
1php artisan migrate --isolated
要使用此功能,您的应用程序必须使用memcached
、redis
、dynamodb
、database
、file
或array
缓存驱动程序作为应用程序的默认缓存驱动程序。此外,所有服务器必须与同一个中央缓存服务器通信。
强制迁移在生产环境中运行
某些迁移操作具有破坏性,这意味着它们可能会导致您丢失数据。为了防止您在生产数据库上运行这些命令,在执行命令之前,系统会Prompts您确认。要强制命令在不Prompts的情况下运行,请使用以下--force
标志:
1php artisan migrate --force
回滚迁移
要回滚最新的迁移操作,可以使用rollback
Artisan 命令。此命令会回滚上一“批”迁移,其中可能包含多个迁移文件:
1php artisan migrate:rollback
step
您可以通过在命令中添加选项来回滚有限数量的迁移rollback
。例如,以下命令将回滚最近的五次迁移:
1php artisan migrate:rollback --step=5
batch
您可以通过在命令中指定选项来回滚特定批次的迁移rollback
,该batch
选项对应于应用程序migrations
数据库表中的批次值。例如,以下命令将回滚第三批次中的所有迁移:
1php artisan migrate:rollback --batch=3
如果您希望查看迁移将执行的 SQL 语句而不实际运行它们,您可以--pretend
为migrate:rollback
命令提供标志:
1php artisan migrate:rollback --pretend
该migrate:reset
命令将回滚所有应用程序的迁移:
1php artisan migrate:reset
使用单个命令回滚和迁移
该migrate:refresh
命令将回滚所有迁移,然后执行该migrate
命令。此命令实际上会重新创建整个数据库:
1php artisan migrate:refresh2 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:fresh2 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);
要删除现有表,您可以使用drop
或dropIfExists
方法:
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});
可用的列类型
架构构建器蓝图提供了多种方法,这些方法与您可以添加到数据库表中的不同类型的列相对应。下表列出了每种可用的方法:
布尔类型
字符串和文本类型
数字类型
bigIncrements 大整数 十进制 双倍的 漂浮 ID 增量 整数 中等增量 中整数 smallIncrements 小整数 tinyIncrements 微小整数 无符号大整数 无符号整数 无符号中整数 无符号小整数 无符号小整数
日期和时间类型
二进制类型
对象和 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 时,您可以传递length
和fixed
参数来创建VARBINARY
或BINARY
等效列:
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 BIGINT
、CHAR(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}_id
、UNSIGNED BIGINT
或CHAR(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_at
Eloquent “软删除”功能所需的时间戳:
1$table->softDeletesTz('deleted_at', precision: 0);
softDeletes()
该softDeletes
方法添加了一个可空的deleted_at
TIMESTAMP
等效列,其精度可选为秒的小数部分。此列用于存储deleted_at
Eloquent “软删除”功能所需的时间戳:
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_at
(updated_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(): void14 {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});
修改列时,必须在列定义中显式包含所有要保留的修饰符 - 任何缺失的属性都将被删除。例如,要保留unsigned
、default
和comment
属性,必须在更改列时显式调用每个修饰符:
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_id 和morphable_type 列。 |
$table->dropRememberToken(); |
删除该remember_token 列。 |
$table->dropSoftDeletes(); |
删除该deleted_at 列。 |
$table->dropSoftDeletesTz(); |
方法的别名dropSoftDeletes() 。 |
$table->dropTimestamps(); |
删除created_at 和updated_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
Schema 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 |
已加载现有的数据库架构转储。 |