数据库:迁移
介绍
迁移就像是数据库的版本控制,允许团队轻松修改和共享应用程序的数据库架构。迁移通常与 Laravel 的架构构建器配对使用,以便轻松构建应用程序的数据库架构。
Laravel 的 Schema
facade 提供了与数据库无关的支持,用于创建和操作表。它在所有 Laravel 支持的数据库系统中共享相同的表达式流畅 API。
生成迁移
要创建迁移,请使用 make:migration
Artisan 命令:
php artisan make:migration create_users_table
新迁移将被放置在您的 database/migrations
目录中。每个迁移文件名都包含一个时间戳,Laravel 可以通过它来确定迁移的顺序。
--table
和 --create
选项也可以用来指示表的名称以及迁移是否将创建新表。这些选项只是预填充生成的迁移存根文件中的指定表:
php artisan make:migration add_votes_to_users_table --table=users
php artisan make:migration create_users_table --create=users
如果您想为生成的迁移指定自定义输出路径,可以在执行 make:migration
命令时使用 --path
选项。提供的路径应相对于应用程序的基路径。
迁移结构
迁移类包含两个方法:up
和 down
。up
方法用于向数据库添加新表、列或索引,而 down
方法应简单地反转 up
方法执行的操作。
在这两个方法中,您可以使用 Laravel 架构构建器来表达性地创建和修改表。要了解 Schema
构建器上可用的所有方法,请查看其文档。例如,让我们看一个创建 flights
表的示例迁移:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateFlightsTable extends Migration
{
/**
* 运行迁移。
*
* @return void
*/
public function up()
{
Schema::create('flights', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
/**
* 反转迁移。
*
* @return void
*/
public function down()
{
Schema::drop('flights');
}
}
运行迁移
要运行应用程序的所有未完成迁移,请使用 migrate
Artisan 命令。如果您使用的是 Homestead 虚拟机,应在 VM 内运行此命令:
php artisan migrate
如果在运行迁移时收到“类未找到”错误,请尝试运行 composer dump-autoload
命令并重新发出迁移命令。
强制迁移在生产环境中运行
某些迁移操作是破坏性的,意味着它们可能导致数据丢失。为了保护您不在生产数据库上运行这些命令,执行这些命令之前会提示您确认。要强制命令在没有提示的情况下运行,请使用 --force
标志:
php artisan migrate --force
回滚迁移
要回滚最新的迁移“操作”,可以使用 rollback
命令。请注意,这会回滚上次运行的“批次”迁移,其中可能包含多个迁移文件:
php artisan migrate:rollback
migrate:reset
命令将回滚应用程序的所有迁移:
php artisan migrate:reset
在单个命令中回滚/迁移
migrate:refresh
命令将首先回滚所有数据库迁移,然后运行 migrate
命令。此命令有效地重新创建整个数据库:
php artisan migrate:refresh
php artisan migrate:refresh --seed
编写迁移
创建表
要创建新的数据库表,请在 Schema
facade 上使用 create
方法。create
方法接受两个参数。第一个是表的名称,第二个是接收 Blueprint
对象的 Closure
,用于定义新表:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
});
当然,在创建表时,您可以使用架构构建器的任何列方法来定义表的列。
检查表/列是否存在
您可以使用 hasTable
和 hasColumn
方法轻松检查表或列是否存在:
if (Schema::hasTable('users')) {
//
}
if (Schema::hasColumn('users', 'email')) {
//
}
连接和存储引擎
如果要在非默认连接的数据库上执行架构操作,请使用 connection
方法:
Schema::connection('foo')->create('users', function ($table) {
$table->increments('id');
});
要为表设置存储引擎,请在架构构建器上设置 engine
属性:
Schema::create('users', function ($table) {
$table->engine = 'InnoDB';
$table->increments('id');
});
重命名/删除表
要重命名现有数据库表,请使用 rename
方法:
Schema::rename($from, $to);
要删除现有表,可以使用 drop
或 dropIfExists
方法:
Schema::drop('users');
Schema::dropIfExists('users');
创建列
要更新现有表,我们将使用 Schema
facade 上的 table
方法。与 create
方法一样,table
方法接受两个参数:表的名称和接收 Blueprint
实例的 Closure
,我们可以使用它来向表中添加列:
Schema::table('users', function ($table) {
$table->string('email');
});
可用的列类型
当然,架构构建器包含多种列类型,您可以在构建表时使用:
命令 | 描述 |
---|---|
$table->bigIncrements('id'); | 使用“UNSIGNED BIG INTEGER”等效的递增 ID(主键)。 |
$table->bigInteger('votes'); | 数据库的 BIGINT 等效。 |
$table->binary('data'); | 数据库的 BLOB 等效。 |
$table->boolean('confirmed'); | 数据库的 BOOLEAN 等效。 |
$table->char('name', 4); | 带长度的 CHAR 等效。 |
$table->date('created_at'); | 数据库的 DATE 等效。 |
$table->dateTime('created_at'); | 数据库的 DATETIME 等效。 |
$table->decimal('amount', 5, 2); | 带精度和刻度的 DECIMAL 等效。 |
$table->double('column', 15, 8); | 带精度的 DOUBLE 等效,总共 15 位,小数点后 8 位。 |
$table->enum('choices', ['foo', 'bar']); | 数据库的 ENUM 等效。 |
$table->float('amount'); | 数据库的 FLOAT 等效。 |
$table->increments('id'); | 使用“UNSIGNED INTEGER”等效的递增 ID(主键)。 |
$table->integer('votes'); | 数据库的 INTEGER 等效。 |
$table->json('options'); | 数据库的 JSON 等效。 |
$table->jsonb('options'); | 数据库的 JSONB 等效。 |
$table->longText('description'); | 数据库的 LONGTEXT 等效。 |
$table->mediumInteger('numbers'); | 数据库的 MEDIUMINT 等效。 |
$table->mediumText('description'); | 数据库的 MEDIUMTEXT 等效。 |
$table->morphs('taggable'); | 添加 INTEGER taggable_id 和 STRING taggable_type 。 |
$table->nullableTimestamps(); | 与 timestamps() 相同,但允许 NULL。 |
$table->rememberToken(); | 添加 remember_token 作为 VARCHAR(100) NULL。 |
$table->smallInteger('votes'); | 数据库的 SMALLINT 等效。 |
$table->softDeletes(); | 添加 deleted_at 列用于软删除。 |
$table->string('email'); | VARCHAR 等效列。 |
$table->string('name', 100); | 带长度的 VARCHAR 等效。 |
$table->text('description'); | 数据库的 TEXT 等效。 |
$table->time('sunrise'); | 数据库的 TIME 等效。 |
$table->tinyInteger('numbers'); | 数据库的 TINYINT 等效。 |
$table->timestamp('added_on'); | 数据库的 TIMESTAMP 等效。 |
$table->timestamps(); | 添加 created_at 和 updated_at 列。 |
$table->uuid('id'); | 数据库的 UUID 等效。 |
列修饰符
除了上面列出的列类型外,还有几个其他列“修饰符”,您可以在添加列时使用。例如,要使列“可为空”,可以使用 nullable
方法:
Schema::table('users', function ($table) {
$table->string('email')->nullable();
});
以下是所有可用列修饰符的列表。此列表不包括索引修饰符:
修饰符 | 描述 |
---|---|
->first() | 将列放在表的“第一位”(仅限 MySQL) |
->after('column') | 将列放在另一个列的“后面”(仅限 MySQL) |
->nullable() | 允许在列中插入 NULL 值 |
->default($value) | 为列指定“默认”值 |
->unsigned() | 将 integer 列设置为 UNSIGNED |
修改列
先决条件
在修改列之前,请确保在 composer.json
文件中添加 doctrine/dbal
依赖项。Doctrine DBAL 库用于确定列的当前状态并创建所需的 SQL 查询以对列进行指定的调整。
更新列属性
change
方法允许您将现有列修改为新类型,或修改列的属性。例如,您可能希望增加字符串列的大小。要查看 change
方法的实际应用,让我们将 name
列的大小从 25 增加到 50:
Schema::table('users', function ($table) {
$table->string('name', 50)->change();
});
我们还可以将列修改为可为空:
Schema::table('users', function ($table) {
$table->string('name', 50)->nullable()->change();
});
重命名列
要重命名列,可以在 Schema 构建器上使用 renameColumn
方法。在重命名列之前,请确保在 composer.json
文件中添加 doctrine/dbal
依赖项:
Schema::table('users', function ($table) {
$table->renameColumn('from', 'to');
});
目前不支持在包含 enum
列的表中重命名列。
删除列
要删除列,请在 Schema 构建器上使用 dropColumn
方法:
Schema::table('users', function ($table) {
$table->dropColumn('votes');
});
您可以通过将列名数组传递给 dropColumn
方法,从表中删除多个列:
Schema::table('users', function ($table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});
在从 SQLite 数据库中删除列之前,您需要在 composer.json
文件中添加 doctrine/dbal
依赖项,并在终端中运行 composer update
命令以安装库。
在使用 SQLite 数据库时,在单个迁移中删除或修改多个列是不支持的。
创建索引
架构构建器支持多种类型的索引。首先,让我们看一个示例,该示例指定列的值应唯一。要创建索引,我们可以简单地将 unique
方法链接到列定义上:
$table->string('email')->unique();
或者,您可以在定义列后创建索引。例如:
$table->unique('email');
您甚至可以将列数组传递给索引方法以创建复合索引:
$table->index(['account_id', 'created_at']);
可用的索引类型
命令 | 描述 |
---|---|
$table->primary('id'); | 添加主键。 |
$table->primary(['first', 'last']); | 添加复合键。 |
$table->unique('email'); | 添加唯一索引。 |
$table->index('state'); | 添加基本索引。 |
删除索引
要删除索引,您必须指定索引的名称。默认情况下,Laravel 会自动为索引分配一个合理的名称。只需连接表名、索引列名和索引类型即可。以下是一些示例:
命令 | 描述 |
---|---|
$table->dropPrimary('users_id_primary'); | 从“users”表中删除主键。 |
$table->dropUnique('users_email_unique'); | 从“users”表中删除唯一索引。 |
$table->dropIndex('geo_state_index'); | 从“geo”表中删除基本索引。 |
如果您将列数组传递给删除索引的方法,则会根据表名、列和键类型自动生成常规索引名称。
Schema::table('geo', function ($table) {
$table->dropIndex(['state']); // 删除索引 'geo_state_index'
});
外键约束
Laravel 还提供了创建外键约束的支持,这些约束用于在数据库级别强制执行参照完整性。例如,让我们在 posts
表上定义一个 user_id
列,该列引用 users
表上的 id
列:
Schema::table('posts', function ($table) {
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
});
您还可以为约束的“on delete”和“on update”属性指定所需的操作:
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
要删除外键,可以使用 dropForeign
方法。外键约束使用与索引相同的命名约定。因此,我们将连接表名和约束中的列,然后在名称后加上“_foreign”:
$table->dropForeign('posts_user_id_foreign');
或者,您可以传递一个数组值,当删除时将自动使用常规约束名称:
$table->dropForeign(['user_id']);