[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