[TOC]
# 数据库迁移
## 生成迁移
```
$ php artisan make:migration create_users_table
```
新的迁移位于`database/migrations`目录下。每个迁移文件名都包含时间戳,以便让 Laravel 确认迁移的顺序。
`--table`和`--create`选项可用来指定数据表的名称,或是该迁移被执行时是否将创建的新数据表。这些选项需在预生成迁移文件时填入指定的数据表:
```
php artisan make:migration create_users_table --create=users
php artisan make:migration add_votes_to_users_table --table=users
```
如果你想要指定生成迁移指定一个自定义输出路径,则可以在运行`make:migration`命令时添加`--path`选项,给定的路径必须是相对于应用程序的基本路径。
## 迁移结构
迁移类通常会包含 2 个方法:`up`和`down`。`up`方法用于添加新的数据表, 字段或者索引到数据库, 而`down`方法就是`up`方法的反操作,和`up`里的操作相反。
```
<?php
use Illuminate\Support\Facades\Schema;
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');
}
}
```
## 运行迁移
```
// 运行所有未完成的迁移
$ php artisan migrate
```
> 注意:如果你正在使用 Homestead 虚拟机,你应该在你的虚拟机里执行这个命令。
### 在生产环境强制执行迁移
```
// 可能会导致数据丢失
$ php artisan migrate --force
```
### 回滚迁移
```
// 回滚最后一次迁移的操作,其中可能包含多个迁移文件
$ php artisan migrate:rollback
// 回滚最近五次迁移
$ php artisan migrate:rollback --step=5
// 回滚应用程序中的所有迁移
$ php artisan migrate:reset
```
### 使用单个命令来执行回滚或迁移
```
// 重建数据库
php artisan migrate:refresh
// 刷新数据库结构并执行数据填充
php artisan migrate:refresh --seed
// 回滚最后五次迁移并重新执行
php artisan migrate:refresh --step=5
```
### 删除所有表 & 迁移
```
// 从数据库中删除所有表,然后执行 migrate 命令
php artisan migrate:fresh
// 从数据库中删除所有表并执行数据填充
php artisan migrate:fresh --seed
```
## 数据表
### 创建数据表
`create`方法接受两个参数:第一个参数为数据表的名称,第二个参数是`Closure`,此闭包会接收一个用于定义新数据表的`Blueprint`对象。
```
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
});
```
### 检查数据表 / 字段是否存在
```
if (Schema::hasTable('users')) {
//
}
if (Schema::hasColumn('users', 'email')) {
//
}
```
### 数据库连接 & 表选项
```
Schema::connection('foo')->create('users', function (Blueprint $table) {
$table->increments('id');
});
```
### 其他表选项
命令 | 描述
------- | -----------
`$table->engine = 'InnoDB';` | 指定表存储引擎 (MySQL)。
`$table->charset = 'utf8';` | 指定数据表的默认字符集 (MySQL)。
`$table->collation = 'utf8_unicode_ci';` | 指定数据表默认的排序规则 (MySQL)。
`$table->temporary();` | 创建临时表 (不支持SQL Server)。
### 重命名 / 删除数据表
```
Schema::rename($from, $to);
Schema::drop('users');
Schema::dropIfExists('users');
```
### 重命名带外键的数据表
在重命名表之前,你应该验证表上的任何外键约束在迁移文件中都有明确的名称,而不是让 Laravel 按照约定来设置一个名称。否则,外键的约束名称将引用旧表名。
## 字段
### 创建字段
`table`方法可以更新现有的数据表,`table`方法会接受两个参数:一个是数据表的名称,另一个则是接收可以用来向表中添加字段的`Blueprint`实例的闭包:
```
Schema::table('users', function (Blueprint $table) {
$table->string('email');
});
```
### 可用的字段类型
数据库结构生成器包含构建表时可以指定的各种字段类型:
命令 | 描述
------- | -----------
`$table->bigIncrements('id');` | 递增 ID(主键),相当于「UNSIGNED BIG INTEGER」
`$table->bigInteger('votes');` | 相当于 BIGINT
`$table->binary('data');` | 相当于 BLOB
`$table->boolean('confirmed');` | 相当于 BOOLEAN
`$table->char('name', 100);` | 相当于带有长度的 CHAR
`$table->date('created_at');` | 相当于 DATE
`$table->dateTime('created_at');` | 相当于 DATETIME
`$table->dateTimeTz('created_at');` | 相当于带时区 DATETIME
`$table->decimal('amount', 8, 2);` | 相当于带有精度与基数 DECIMAL
`$table->double('amount', 8, 2);` | 相当于带有精度与基数 DOUBLE
`$table->enum('level', ['easy', 'hard']);` | 相当于 ENUM
`$table->float('amount', 8, 2);` | 相当于带有精度与基数 FLOAT
`$table->geometry('positions');` | 相当于 GEOMETRY
`$table->geometryCollection('positions');` | 相当于 GEOMETRYCOLLECTION
`$table->increments('id');` | 递增的 ID (主键),相当于「UNSIGNED INTEGER」
`$table->integer('votes');` | 相当于 INTEGER
`$table->ipAddress('visitor');` | 相当于 IP 地址
`$table->json('options');` | 相当于 JSON
`$table->jsonb('options');` | 相当于 JSONB
`$table->lineString('positions');` | 相当于 LINESTRING
`$table->longText('description');` | 相当于 LONGTEXT
`$table->macAddress('device');` | 相当于 MAC 地址
`$table->mediumIncrements('id');` | 递增 ID (主键) ,相当于「UNSIGNED MEDIUM INTEGER」
`$table->mediumInteger('votes');` | 相当于 MEDIUMINT
`$table->mediumText('description');` | 相当于 MEDIUMTEXT
`$table->morphs('taggable');` | 相当于加入 Unsigned BIGINT `taggable_id` 与字符串 `taggable_type`
`$table->multiLineString('positions');` | 相当于 MULTILINESTRING
`$table->multiPoint('positions');` | 相当于 MULTIPOINT
`$table->multiPolygon('positions');` | 相当于 MULTIPOLYGON
`$table->nullableMorphs('taggable');` | 相当于可空版本的 `morphs()` 字段
`$table->nullableTimestamps();` | 相当于可空版本的 `timestamps()` 字段
`$table->point('position');` | 相当于 POINT
`$table->polygon('positions');` | 相当于 POLYGON
`$table->rememberToken();` | 相当于可空版本的 VARCHAR(100) 的 `remember_token` 字段
`$table->smallIncrements('id');` | 递增 ID (主键) ,相当于「UNSIGNED SMALL INTEGER」
`$table->smallInteger('votes');` | 相当于 SMALLINT
`$table->softDeletes();` | 相当于为软删除添加一个可空的 `deleted_at` 字段
`$table->softDeletesTz();` | 相当于为软删除添加一个可空的 带时区的 `deleted_at` 字段
`$table->string('name', 100);` | 相当于带长度的 VARCHAR
`$table->text('description');` | 相当于 TEXT
`$table->time('sunrise');` | 相当于 TIME
`$table->timeTz('sunrise');` | 相当于带时区的 TIME
`$table->timestamp('added_on');` | 相当于 TIMESTAMP
`$table->timestampTz('added_on');` | 相当于带时区的 TIMESTAMP
`$table->timestamps();` | 相当于可空的 `created_at` 和 `updated_at` TIMESTAMP
`$table->timestampsTz();` | 相当于可空且带时区的 `created_at` 和 `updated_at` TIMESTAMP
`$table->tinyIncrements('id');` | 相当于自动递增 UNSIGNED TINYINT
`$table->tinyInteger('votes');` | 相当于 TINYINT
`$table->unsignedBigInteger('votes');` | 相当于 Unsigned BIGINT
`$table->unsignedDecimal('amount', 8, 2);` | 相当于带有精度和基数的 UNSIGNED DECIMAL
`$table->unsignedInteger('votes');` | 相当于 Unsigned INT
`$table->unsignedMediumInteger('votes');` | 相当于 Unsigned MEDIUMINT
`$table->unsignedSmallInteger('votes');` | 相当于 Unsigned SMALLINT
`$table->unsignedTinyInteger('votes');` | 相当于 Unsigned TINYINT
`$table->uuid('id');` | 相当于 UUID
`$table->year('birth_year');` | 相当于 YEAR
### 字段修饰
```
// 允许字段为空
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});
```
### 字段修饰符列表
Modifier | Description
-------- | -----------
`->after('column')` | 将此字段放置在其它字段 "之后" (MySQL)
`->autoIncrement()` | 将 INTEGER 类型的字段设置为自动递增的主键
`->charset('utf8')` | 指定一个字符集 (MySQL)
`->collation('utf8_unicode_ci')` | 指定列的排序规则 (MySQL/SQL Server)
`->comment('my comment')` | 为字段增加注释 (MySQL)
`->default($value)` | 为字段指定 "默认" 值
`->first()` | 将此字段放置在数据表的 "首位" (MySQL)
`->nullable($value = true)` | 此字段允许写入 NULL 值(默认情况下)
`->storedAs($expression)` | 创建一个存储生成的字段 (MySQL)
`->unsigned()` | 设置 INTEGER 类型的字段为 UNSIGNED (MySQL)
`->useCurrent()` | 将 TIMESTAMP 类型的字段设置为使用 CURRENT_TIMESTAMP 作为默认值
`->virtualAs($expression)` | 创建一个虚拟生成的字段 (MySQL)
### 修改字段
#### 先决条件
确保 composer.json 文件内已经加入 doctrine/dbal 依赖
Doctrine DBAL 库用于确定字段的当前状态, 并创建对该字段进行指定调整所需的 SQL 查询
```
$ composer require doctrine/dbal
```
#### 更新字段属性
```
// change 方法可以将现有的字段类型修改为新的类型或修改属性。
Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->change();
});
// 字段允许为空
Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->nullable()->change();
});
```
>[success] 注意:只有下面的字段类型能被 "修改": bigInteger、 binary、 boolean、date、dateTime、dateTimeTz、decimal、integer、json、 longText、mediumText、smallInteger、string、text、time、 unsignedBigInteger、unsignedInteger and unsignedSmallInteger。
#### 重命名字段
```
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});
```
> 注意:当前不支持 enum 类型的字段重命名。
#### 删除字段
从 SQLite 数据库删除字段前,确保`composer.json`文件内已经加入`doctrine/dbal`依赖。
```
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});
// 删除多个字段
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});
```
> 注意:不支持在使用 SQLite 数据库时在单个迁移中删除或修改多个字段。
#### 可用的命令别名
Command | Description
------- | -----------
`$table->dropRememberToken();` | 删除 `remember_token` 字段。
`$table->dropSoftDeletes();` | 删除 `deleted_at` 字段。
`$table->dropSoftDeletesTz();` | `dropSoftDeletes()` 方法的别名。
`$table->dropTimestamps();` | 删除 `created_at` and `updated_at` 字段。
`$table->dropTimestampsTz();` | `dropTimestamps()` 方法的别名。
## 索引
### 创建索引
```
// 唯一索引
$table->string('email')->unique();
$table->unique('email');
// 复合索引
$table->index(['account_id', 'created_at']);
// 自定义索引名称
$table->unique('email', 'unique_email');
```
### 可用的索引类型
每个索引方法都接受一个可选的第二个参数来指定索引的名称。如果省略,名称将根据表和列的名称生成。
命令 | 描述
------- | -----------
`$table->primary('id');` | 添加主键
`$table->primary(['id', 'parent_id']);` | 添加复合键
`$table->unique('email');` | 添加唯一索引
`$table->index('state');` | 添加普通索引
`$table->spatialIndex('location');` | 添加空间索引(不支持 SQLite)
### 索引长度 & Mysql / MariaDB
Laravel 默认使用`utf8mb4`编码,它支持在数据库中储存`emojis`。如果你是在版本低于 5.7.7 的 MySQL 或者版本低于 10.2.2 的 MariaDB 上创建索引,那你就需要手动配置数据库迁移的默认字符串长度。
在`AppServiceProvider`中调用`Schema::defaultStringLength`方法配置,或者也可以选择开启数据库的`innodb_large_prefix`选项。
```
use Illuminate\Support\Facades\Schema;
/**
* 引导任何应用程序服务
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}
```
### 重命名索引
```
// 当前索引名称为第一参数,新索引名称为第二参数
$table->renameIndex('from', 'to')
```
### 删除索引
若要删除索引,则必须指定索引的名称。Laravel 默认会自动将数据库名称、索引的字段名及索引类型简单地连接在一起作为名称。举例如下:
命令 | 描述
------- | -----------
`$table->dropPrimary('users_id_primary');` | 从 `users` 表中删除主键
`$table->dropUnique('users_email_unique');` | 从 `users` 表中删除唯一索引
`$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' 索引
});
```
### 外键约束
```
// 在 posts 表上定义一个引用 users 表的 id 字段的 user_id 字段
Schema::table('posts', function (Blueprint $table) {
$table->unsignedInteger('user_id');
$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']);
// 在迁移文件中开启或关闭外键约束
Schema::enableForeignKeyConstraints();
Schema::disableForeignKeyConstraints();
```
> 注意:SQLite 默认禁用外键约束。 使用 SQLite 时,请确保在数据库配置中启用 [启用外键支持],然后再尝试在迁移中创建它们。
- 入门指南
- 安装
- 部署
- 基础功能
- 路由
- 中间件
- CSRF 保护
- 控制器
- 请求
- 响应
- 视图
- URL
- Session
- 表单验证
- 错误
- 日志
- 前端开发
- Blade 模板
- 本地化
- 脚手架
- 编译资源 Mix
- 安全相关
- 用户认证
- API 认证
- 综合话题
- 命令行
- 广播
- 缓存
- 集合
- 事件
- 文件存储
- 辅助函数
- 邮件发送
- 消息通知
- 扩展包开发
- 队列
- 任务调度
- 数据库
- 快速入门
- 查询构造器
- 分页
- 数据库迁移
- 数据填充
- Redis
- Eloquent ORM
- 快速入门
- 速查表
- Artisan
- Auth
- Blade
- Cache
- Collection
- Composer
- Config
- Container
- Cookie
- DB
- Environment
- Event
- File
- Helper
- Input
- Lang
- Log
- Model
- Pagination
- Queue
- Redirect
- Request
- Response
- Route
- SSH
- Schema
- Security
- Session
- Storage
- String
- URL
- UnitTest
- Validation
- View