数据库迁移
数据库:迁移
简介
迁移就像是对数据库进行的版本控制,让您的团队能够轻松地去定义和共享程序的数据库结构。如果团队中某个成员在他本地的数据库环境中手动的添加了某个字段,并且将更改提交到了源代码管理,那么您就面临数据库迁移所解决的问题。
Laravel 的 Schema
facade 提供了数据库相关的支持,可以在所有 Laravel 支持的数据库管理系统中创建和操作表。通常,迁移将使用此 Facade 创建和修改数据库的数据表和字段。
生成迁移
使用 make:migration
Artisan 命令 来创建迁移。新的迁移文件会放在 database/migrations
目录。所有的迁移文件名称都会包含一个时间戳,Laravel 将据此决定迁移文件运行的顺序。
php artisan make:migration create_flights_table
Laravel 将使用迁移的名称来尝试猜测数据表的名称,以及迁移是否将创建一个新的数据表。如果 Laravel 能够从迁移名称中确定数据表名,它将会用指定的数据表名预填充生成的迁移文件。否则,您只需手动指定迁移文件中的数据表。
如果要为生成的迁移指定自定义路径,您可以在执行 make:migration
命令时使用 --path
选项。给定的路径应该相对于应用程序的基本路径。
技巧:可以使用 stub publishing 自定义发布
压缩迁移
在构建应用程序时,可能会随着时间的推移积累越来越多的迁移。这可能会导致您的 database/migrations
目录因为数百次迁移而变得臃肿。你如果愿意的话,可以将迁移「压缩」到单个SQL文件中。如果你想这样做,请先执行 schema:dump
命令:
php artisan schema:dump
// 转储当前数据库架构并删除所有现有迁移。。。
php artisan schema:dump --prune
执行此命令时, Laravel 将向应用程序的 “database/schema” 目录写入一个 “schema” 文件。现在,当您尝试迁移数据库而没有执行其他迁移时, Laravel 将首先执行模式文件的SQL语句。在执行数据库结构文件的语句之后,Laravel 将执行不属于数据库结构的剩余的所有迁移。
您应该将数据库结构文件提交到源代码管理工具里( git / svn 等),以便团队中的其他新开发人员可以快速创建应用程序的初始数据库结构。
注意:压缩迁移仅适用于 MySQL 、 PostgreSQL 和 SQLite 数据库,并使用数据库命令行的客户端。另外,数据库结构不能还原到内存中的SQLite数据库。
结构迁移
迁移类包含两个方法:up
和 down
。up
方法用于向数据库中添加新表、列或索引,而 down
方法用于撤销 up
方法执行的操作。
在这两种方法中,你可以使用 Laravel schema 构建器显式地创建和修改表。如果想要了解 Schema
构建器的所有方法,点此查看文档。例如,下述迁移创建了一个 flights
表:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateFlightsTable extends Migration
{
/**
* 运行迁移
*
* @return void
*/
public function up()
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
/**
* 回滚迁移
*
* @return void
*/
public function down()
{
Schema::drop('flights');
}
}
运行迁移
执行 Artisan 命令 migrate
,来运行所有未执行过的迁移:
php artisan migrate
如果你想查看目前已经执行了哪些迁移,可以使用 Artisan 命令 migrate:status
:
php artisan migrate:status
在生产环境中执行强制迁移
有些迁移操作是破坏性的,这意味着它们可能会导致数据丢失。为了防止您对生产数据库运行这些命令,在执行这些命令之前,系统将提示您进行确认。如果要在运行强制命令的时候去掉提示,需要加上 --force
标志:
php artisan migrate --force
回滚迁移
如果要回滚最后一次迁移操作,可以使用 Artisan 命令 rollback
。该命令会回滚最后「一批」的迁移,这可能包含多个迁移文件:
php artisan migrate:rollback
通过向 rollback
命令加上 step
参数,可以回滚指定数量的迁移。例如,以下命令将回滚最后五个迁移:
php artisan migrate:rollback --step=5
命令 migrate:reset
会回滚应用已运行过的所有迁移:
php artisan migrate:reset
使用单个命令同时进行回滚和迁移操作
命令 migrate:refresh
首先会回滚已运行过的所有迁移,随后会执行 migrate
。这一命令可以高效地重建你的整个数据库:
php artisan migrate:refresh
// 重置数据库,并运行所有的 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
在删去所有数据表的过程中,会无视它们的前缀。如果数据库涉及到其它应用,使用该命令须十分小心。
数据表
创建数据表
接下来我们将使用 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();
});
创建表时,可以使用数据库结构构建器中的任何 列方法来定义表的列。
检查表/列是否存在
您可以使用 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';
// ...
});
使用 MySQL 时,可以使用 charset
and collation
属性指定创建表的字符集和排序规则:
Schema::create('users', function (Blueprint $table) {
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
// ...
});
temporary
方法可用于将表标识为「临时」状态。临时表仅对当前连接的数据库会话可见,当连接关闭时会自动删除:
Schema::create('calculations', function (Blueprint $table) {
$table->temporary();
// ...
});
表的更新
Schema
facade 上的 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');
});
有效的列类型
模式构建器模型提供了与可以添加到数据库表中的不同列类型相对应的各种方法。 下表中列出了每种可用的方法:
<code>bigIncrements()</code> {#collection-method}
bigIncrements
方法用于在数据表中创建一个自增的 UNSIGNED BIGINT
类型(主键)的列:
$table->bigIncrements('id');
<code>bigInteger()</code> {#collection-method}
bigInteger
方法用于在数据表中创建一个 BIGINT
类型的列:
$table->bigInteger('votes');
<code>binary()</code> {#collection-method}
binary
方法用于在数据表中创建一个 BLOB
类型的列:
$table->binary('photo');
<code>boolean()</code> {#collection-method}
boolean
方法用于在数据表中创建一个 BOOLEAN
类型的列:
$table->boolean('confirmed');
<code>char()</code> {#collection-method}
char
方法用于在数据表中创建一个 CHAR
类型的列,长度由参数指定:
$table->char('name', 100);
<code>dateTimeTz()</code> {#collection-method}
dateTimeTz
方法用于在数据表中创建一个 DATETIME
类型(附有 timezone
)的列,可选参数为精度的总位数:
$table->dateTimeTz('created_at', $precision = 0);
<code>dateTime()</code> {#collection-method}
dateTime
方法用于在数据表中创建一个 DATETIME
类型的列,可选参数为精度的总位数:
$table->dateTime('created_at', $precision = 0);
<code>date()</code> {#collection-method}
date
方法用于在数据表中创建一个 DATE
类型的列:
$table->date('created_at');
<code>decimal()</code> {#collection-method}
decimal
方法用于在数据表中创建一个 DECIMAL
类型的列,可选参数分别为有效字数总位数、小数部分总位数:
$table->decimal('amount', $precision = 8, $scale = 2);
<code>double()</code> {#collection-method}
double
方法用于在数据表中创建一个 DOUBLE
类型的列,可选参数分别为有效字数总位数、小数部分总位数:
$table->double('amount', 8, 2);
<code>enum()</code> {#collection-method}
enum
方法用于在数据表中创建一个 ENUM
类型的列,合法的值列表由参数指定:
$table->enum('difficulty', ['easy', 'hard']);
<code>float()</code> {#collection-method}
float
方法用于在数据表中创建一个 FLOAT
类型的列,可选参数分别为有效字数总位数、小数部分总位数:
$table->float('amount', 8, 2);
<code>foreignId()</code> {#collection-method}
foreignId
方法是 unsignedBigInteger
的别名:
$table->foreignId('user_id');
<code>geometryCollection()</code> {#collection-method}
geometryCollection
方法相当于 GEOMETRYCOLLECTION
:
$table->geometryCollection('positions');
<code>geometry()</code> {#collection-method}
geometry
方法相当于 GEOMETRY
:
$table->geometry('positions');
<code>id()</code> {#collection-method}
id
方法是bigIncrements
的别名.默认情况下,该方法将创建一个 id
列; 但是,如果要为列指定不同的名称,则可以传递列名:
$table->id();
<code>increments()</code> {#collection-method}
increments
方法创建一个自动递增相当于 UNSIGNED INTEGER
的列作为主键:
$table->increments('id');
<code>integer()</code> {#collection-method}
integer
方法相当于 INTEGER
:
$table->integer('votes');
<code>ipAddress()</code> {#collection-method}
ipAddress
方法相当于 VARCHAR
:
$table->ipAddress('visitor');
<code>json()</code> {#collection-method}
json
方法相当于 JSON
:
$table->json('options');
<code>jsonb()</code> {#collection-method}
jsonb
方法相当于 JSONB
:
$table->jsonb('options');
<code>lineString()</code> {#collection-method}
lineString
方法相当于 LINESTRING
:
$table->lineString('positions');
<code>longText()</code> {#collection-method}
longText
方法相当于 LONGTEXT
:
$table->longText('description');
<code>macAddress()</code> {#collection-method}
macAddress
方法创建一个用于保存MAC地址的列. 一些数据库系统(如PostgreSQL),为这种类型的数据提供了专用的类型. 其他数据库系统相当于使用字符串类型:
$table->macAddress('device');
<code>mediumIncrements()</code> {#collection-method}
mediumIncrements
方法用于创建一个 UNSIGNED MEDIUMINT
类型的自动递增的列作为主键:
$table->mediumIncrements('id');
<code>mediumInteger()</code> {#collection-method}
mediumInteger
方法用于创建一个 MEDIUMINT
类型的列:
$table->mediumInteger('votes');
<code>mediumText()</code> {#collection-method}
mediumText
方法用于创建一个 MEDIUMTEXT
类型的列:
$table->mediumText('description');
<code>morphs()</code> {#collection-method}
morphs
方法用于快速创建一个名称为 {column}_id
,类型为 UNSIGNED BIGINT
的列和一个名称为 {column}_type
,类型为 VARCHAR
的列。
这个方法在定义多态关联所需的列时使用。在下面的例子中, taggable_id
和 taggable_type
这两个列会被创建:
$table->morphs('taggable');
<code>multiLineString()</code> {#collection-method}
multiLineString
方法用于创建一个 MULTILINESTRING
类型的列:
$table->multiLineString('positions');
<code>multiPoint()</code> {#collection-method}
multiPoint
方法用于创建一个 MULTIPOINT
类型的列:
$table->multiPoint('positions');
<code>multiPolygon()</code> {#collection-method}
multiPolygon
方法用于创建一个 MULTIPOLYGON
类型的列:
$table->multiPolygon('positions');
<code>nullableTimestamps()</code> {#collection-method}
这个方法和 timestamps 方法类似;需要注意的是此方法创建的列是 nullable
的:
$table->nullableTimestamps(0);
<code>nullableMorphs()</code> {#collection-method}
这个方法和 morphs 方法类似;需要注意的是此方法创建的列是 nullable
的:
$table->nullableMorphs('taggable');
<code>nullableUuidMorphs()</code> {#collection-method}
这个方法和 uuidMorphs 方法类似;需要注意的是此方法创建的列是 nullable
的:
$table->nullableUuidMorphs('taggable');
<code>point()</code> {#collection-method}
相当于 POINT
$table->point('position');
<code>polygon()</code> {#collection-method}
相当于 POLYGON
$table->polygon('position');
<code>rememberToken()</code> {#collection-method}
添加一个允许空值的 VARCHAR (100) 类型的 remember_token
字段,用于存储「记住我」:
$table->rememberToken();
<code>set()</code> {#collection-method}
相当于 SET
$table->set('flavors', ['strawberry', 'vanilla']);
<code>smallIncrements()</code> {#collection-method}
递增 ID(主键),相当于 UNSIGNED SMALLINT
$table->smallIncrements('id');
<code>smallInteger()</code> {#collection-method}
相当于 SMALLINT
$table->smallInteger('votes');
<code>softDeletesTz()</code> {#collection-method}
相当于为软删除添加一个可空的并且带时区的 deleted_at
字段
$table->softDeletesTz($column = 'deleted_at', $precision = 0);
<code>softDeletes()</code> {#collection-method}
相当于为软删除添加一个可空的 deleted_at
字段
$table->softDeletes($column = 'deleted_at', $precision = 0);
<code>string()</code> {#collection-method}
相当于指定长度的 VARCHAR
$table->string('name', 100);
<code>text()</code> {#collection-method}
text
方法创建一个TEXT
等价列:
$table->text('description');
<code>timeTz()</code> {#collection-method}
timeTz
方法创建一个TIME
(带时区)等效列,可选精度(总位数):
$table->timeTz('sunrise', $precision = 0);
<code>time()</code> {#collection-method}
time
方法创建一个等效的TIME
列,具有可选的精度(总位数):
$table->time('sunrise', $precision = 0);
<code>timestampTz()</code> {#collection-method}
timestampTz
方法创建一个 TIMESTAMP
(带有时区)等效列,具有可选精度(总位数):
$table->timestampTz('added_at', $precision = 0);
<code>timestamp()</code> {#collection-method}
timestamp
方法创建一个等效的TIMESTAMP
列,具有可选精度(总位数):
$table->timestamp('added_at', $precision = 0);
<code>timestampsTz()</code> {#collection-method}
timestampsTz
方法创建created_at
和updated_at
TIMESTAMP
(带时区)等效列,可选精度(总位数):
$table->timestampsTz($precision = 0);
<code>timestamps()</code> {#collection-method}
TIMESTAMP
方法创建created_at
和updated_at
TIMESTAMP
等量列,精度可选(总位数):
$table->timestamps($precision = 0);
<code>tinyIncrements()</code> {#collection-method}
tinyIncrements
方法创建一个自动递增的UNSIGNED TINYINT
等效列作为主键:
$table->tinyIncrements('id');
<code>tinyInteger()</code> {#collection-method}
tinyInteger
方法创建一个TINYINT
等价列:
$table->tinyInteger('votes');
<code>unsignedBigInteger()</code> {#collection-method}
unsignedBigInteger
方法创建一个UNSIGNED BIGINT
等价列:
$table->unsignedBigInteger('votes');
<code>unsignedDecimal()</code> {#collection-method}
UNSIGNED DECIMAL
方法创建一个UNSIGNED DECIMAL
等效列,具有可选的精度(总位数)和比例(十进制位数):
$table->unsignedDecimal('amount', $precision = 8, $scale = 2);
<code>unsignedInteger()</code> {#collection-method}
unsignedInteger
方法用于创建一个 UNSIGNED INTEGER
类型的列:
$table->unsignedInteger('votes');
<code>unsignedMediumInteger()</code> {#collection-method}
unsignedMediumInteger
方法用于创建一个 UNSIGNED MEDIUMINT
类型的列:
$table->unsignedMediumInteger('votes');
<code>unsignedSmallInteger()</code> {#collection-method}
unsignedSmallInteger
方法用于创建一个 UNSIGNED SMALLINT
类型的列:
$table->unsignedSmallInteger('votes');
<code>unsignedTinyInteger()</code> {#collection-method}
unsignedTinyInteger
方法用于创建一个 UNSIGNED TINYINT
类型的列:
$table->unsignedTinyInteger('votes');
<code>uuidMorphs()</code> {#collection-method}
uuidMorphs
方法用于快速创建一个名称为 {column}_id
,类型为 CHAR(36)
的列和一个名称为 {column}_type
,类型为 VARCHAR
的列。
这个方法用于定义使用 UUID 标识符的多态关联所需的列时使用。在下面的例子中,taggable_id
和 taggable_type
这两个列将会被创建:
$table->uuidMorphs('taggable');
<code>uuid()</code> {#collection-method}
uuid
方法用于创建一个 UUID
类型的列:
$table->uuid('id');
<code>year()</code> {#collection-method}
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') |
将该列放在其它字段「之后」(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) |
->nullable($value = true) |
允许 NULL 值插入到该列 |
->storedAs($expression) |
创建一个存储生成的列 (MySQL) |
->unsigned() |
设置 INTEGER 类型的字段为 UNSIGNED (MySQL) |
->useCurrent() |
设置 TIMESTAMP 类型的列使用 CURRENT_TIMESTAMP 作为默认值 |
->useCurrentOnUpdate() |
将 TIMESTAMP 类型的列设置为在更新时使用 CURRENT_TIMESTAMP 作为新值 |
->virtualAs($expression) |
创建一个虚拟生成的列 (MySQL) |
->generatedAs($expression) |
使用指定的序列选项创建标识列 (PostgreSQL) |
->always() |
定义序列值优先于标识列的输入 (PostgreSQL) |
默认值表达式
default
修饰符接收一个变量或者一个 \Illuminate\Database\Query\Expression
实例。使用 Expression
实例可以避免使用包含在引号中的值,并且允许你使用特定数据库函数。这在当你需要给 JSON
字段指定默认值的时候特别有用:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Migrations\Migration;
class CreateFlightsTable extends Migration
{
/**
* 运行迁移
*
* @return void
*/
public function up()
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->json('movies')->default(new Expression('(JSON_ARRAY())'));
$table->timestamps();
});
}
}
注意:支持哪些默认值的表示方式取决于你的数据库驱动、数据库版本、还有字段类型。请参考合适的文档使用。还有一点要注意的是,使用数据库特定函数,可能会将你绑牢到特定的数据库驱动上。
列顺序
使用 MySQL 数据库时,可以使用 after
方法在模式中的现有列后添加列:
$table->after('password', function ($table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});
修改列
先决条件
在修饰字段之前,请确保你已经通过 Composer 包管理器安装了 doctrine/dbal
包。Doctrine DBAL 库用于确定字段的当前状态, 并创建对该字段进行指定调整所需的 SQL 查询:
composer require doctrine/dbal
如果你打算修改 timestamp
方法来创建列,你还需要将以下配置添加到应用程序的config/database.php
配置文件中:
use Illuminate\Database\DBAL\TimestampType;
'dbal' => [
'types' => [
'timestamp' => TimestampType::class,
],
],
注意:如果你的应用程序使用 Microsoft SQL 驱动,请确保你已经安装了
doctrine/dbal:^3.0
。
更新字段属性
change
方法可以将现有的字段类型修改为新的类型或修改属性。比如,你可能想增加 string
字段的长度,可以使用 change
方法把 name
字段的长度从 25 增加到 50。所以,我们可以简单的更新字段属性然后调用 change
方法:
Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->change();
});
我们同样可以使用 nullable
将字段修改为允许为空:
Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->nullable()->change();
});
注意:只有以下字段类型能被 「修改」:
bigInteger
,binary
,boolean
,date
,dateTime
,dateTimeTz
,decimal
,integer
,json
,longText
,mediumText
,smallInteger
,string
,text
,time
,unsignedBigInteger
,unsignedInteger
,unsignedSmallInteger
, 和uuid
. 要修改timestamp
字段类型 , Doctrine 类型必须被注册 .
重命名字段
可以使用结构生成器上的 renameColumn
方法来重命名字段。 在重命名字段前,请确保你已经通过 Composer 包管理器安装了 doctrine/dbal
包:
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});
注意:当前不支持
enum
类型的字段重命名。
删除字段
你可以使用结构生成器上的 dropColumn
方法来删除字段。如果你的应用程序使用的是 SQLite 数据库,你必须在调用dropColumn
方法之前通过 Composer 包管理器安装了 doctrine/dbal
包:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});
你可以传递一个字段数组给 dropColumn
方法来删除多个字段:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});
注意:使用 SQLite 数据库时不支持在单个迁移中 删除 或 修改 多个字段。
可用的命令别名
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() 方法别名 |
索引
创建索引
结构生成器支持多种类型的索引。下面的例子中新建了一个值唯一的 email
字段。我们可以将 unique
方法链式地添加到字段定义上来创建索引:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});
或者,你也可以在定义完字段之后创建索引。为此,你应该调用结构生成器上的 unique
方法,此方法应该传入唯一索引的列名称:
$table->unique('email');
你甚至可以将数组传递给索引方法来创建一个复合(或合成)索引:
$table->index(['account_id', 'created_at']);
Laravel 会自动生成一个合理的索引名称,但你也可以传递第二个参数来自定义索引名称:
$table->unique('email', 'unique_email');
可用的索引类型
Laravel 的结构生成器提供了 Laravel 支持的所有类型的索引方法。每个索引方法都接受一个可选的第二个参数来指定索引的名称。如果省略,名称将根据表和列的名称生成。下面是所有可用的索引方法:
命令 | 说明 |
---|---|
$table->primary('id'); |
添加主键 |
$table->primary(['id', 'parent_id']); |
添加复合键 |
$table->unique('email'); |
添加唯一索引 |
$table->index('state'); |
添加普通索引 |
$table->spatialIndex('location'); |
添加空间索引(不支持 SQLite) |
索引长度 & MySQL / MariaDB
默认情况下, Laravel 使用utf8mb4
编码。如果你是在版本低于 5.7.7 的 MySQL 或者版本低于 10.2.2 的 MariaDB 上创建索引,那你就需要手动配置数据库迁移的默认字符串长度。 也就是说,你可以通过在App\Providers\AppServiceProvider
类的boot
方法中调用Schema::defaultStringLength
方法来配置默认字符串长度:
use Illuminate\Support\Facades\Schema;
/**
* 引导任何应用程序「全局配置」
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}
当然,你也可以选择开启数据库的 innodb_large_prefix
选项。至于如何正确开启,请自行查阅数据库文档。
重命名索引
若要重命名索引,你需要调用 renameIndex
方法。此方法接受当前索引名称作为其第一个参数,并将所需名称作为其第二个参数:
$table->renameIndex('from', 'to')
删除索引
若要删除索引,则必须指定索引的名称。Laravel 默认会自动将数据表名称、索引的字段名及索引类型简单地连接在一起作为名称。举例如下:
命令 | 说明 |
---|---|
$table->dropPrimary('users_id_primary'); |
从 「users」 表中删除主键 |
$table->dropUnique('users_email_unique'); |
从 「users」 表中删除 unique 索引 |
$table->dropIndex('geo_state_index'); |
从 「geo」 表中删除基本索引 |
$table->dropSpatialIndex('geo_location_spatialindex'); |
从 「geo」 表中删除空间索引(不支持 SQLite) |
如果将字段数组传给 dropIndex
方法,会删除根据表名、字段和键类型生成的索引名称。
Schema::table('geo', function (Blueprint $table) {
$table->dropIndex(['state']); // 删除 'geo_state_index' 索引
});
外键约束
Laravel 还支持创建用于在数据库层中的强制引用完整性的外键约束。例如,让我们在 posts
表上定义一个引用 users
表的 id
字段的 user_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 额外提供了更简洁的方法,基于约定来提供更好的开发人员体验。上面的示例还可以这么写:
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained();
});
foreignId
方法是 unsignedBigInteger
的别名,而 constrained
方法将使用约定来确定所引用的表名和列名。如果表名与约定不匹配,可以通过将表名作为参数传递给 constrained
方法来指定表名:
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained('users');
});
你可以为约束的「on delete」和「on update」属性指定所需的操作:
$table->foreignId('user_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');
当使用任意 字段修饰符 的时候,必须在调用 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();
注意:SQLite 默认禁用外键约束。使用 SQLite 时,请确保在数据库配置中启用外键支持 然后再尝试在迁移中创建它们。另外, SQLite只在创建表时支持外键,并且将在修改表时不会支持.