# 數據庫 —— 遷移
## 1、簡介
遷移,遷移通常和Laravel的結構構建器結對從而可以很容易地構建應用的數據庫表結構。
Laravel的`Schema`[門面](http://laravelacademy.org/post/97.html)提供了與數據庫系統無關的創建和操縱表的支持,在Laravel所支持的所有數據庫系統中提供一致的、優雅的、平滑的API。
## 2、生成遷移
使用[Artisan命令](http://laravelacademy.org/post/170.html)`make:migration`來創建一個新的遷移:
~~~
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`選項,提供的路徑應該是相對于應用根目錄的。
## 3、遷移結構
遷移類包含了兩個方法:`up`和`down`。`up`方法用于新增表,列或者索引到數據庫,而`down`方法就是`up`方法的反操作,和`up`里的操作相反。
在這兩個方法中你都要用到Laravel的表結構構建器來創建和修改表,想要學習`Schema`構建器的更多有用方法,可以[查看其文檔](http://laravelacademy.org/post/130.html#create-table)。例如,讓我們先看看創建`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');
}
}
~~~
## 4、運行遷移
要運行應用中所有未執行的遷移,可以使用Artisan命令的`migrate`方法。如果你正在使用[Homestead虛擬機](http://laravelacademy.org/post/51.html),應該在你的虛擬機中運行如下這條命令:
~~~
php artisan migrate
~~~
如果再運行時遇到”class not found“的錯誤提示,嘗試運行`composer dump-autoload`命令然后重新運行遷移命令。
**在生產環境中強制運行遷移**
有些遷移操作是毀滅性的,這意味著它們可能造成數據的丟失,為了避免在生產環境數據庫中運行這些命令,你將會在運行這些命令之前被提示并確認。想要強制運行這些命令而不被提示,可以使用`--force`:
~~~
php artisan migrate --force
~~~
### 4.1 回滾遷移
想要回滾最新的一次遷移”操作“,可以使用`rollback`命令,注意這將會回滾最后一批運行的遷移,可能包含多個遷移文件:
~~~
php artisan migrate:rollback
~~~
`migrate:reset`命令將會回滾所有的應用遷移:
~~~
php artisan migrate:reset
~~~
### 4.1.1 在單個命令中回滾/遷移
`migrate:refresh`命令將會先回滾所有數據庫遷移,然后運行`migrate`命令。這個命令可以有效的重建整個數據庫:
~~~
php artisan migrate:refresh
php artisan migrate:refresh --seed
~~~
## 5、編寫遷移
### 5.1?創建表
使用`Schema`門面上的`create`方法來創建新的數據表。`create`方法接收兩個參數,第一個是表名,第二個是獲取用于定義新表的`Blueprint`對象的閉包:
~~~
Schema::create('users', function ($table) {
$table->increments('id');
});
~~~
當然,創建新表的時候,可以使用表結構構建器中的任意[列方法](http://laravelacademy.org/post/130.html#create-columns)來定義數據表的列。
### 5.1.1 檢查表/列是否存在
你可以輕松地使用hasTable和hasColumn方法檢查表或列是否存在:
~~~
if (Schema::hasTable('users')) {
//
}
if (Schema::hasColumn('users', 'email')) {
//
}
~~~
### 5.1.2 連接&存儲引擎
如果你想要在一個數據庫連接上執行表結構操作,該數據庫連接并不是默認數據庫連接,使用`connection`方法:
~~~
Schema::connection('foo')->create('users', function ($table) {
$table->increments('id');
});
~~~
要設置表的存儲引擎,在表結構構建器上設置`engine`屬性:
~~~
Schema::create('users', function ($table) {
$table->engine = 'InnoDB';
$table->increments('id');
});
~~~
### 5.2 重命名/刪除表
要重命名一個已存在的數據表,使用`rename`方法:
~~~
Schema::rename($from, $to);
~~~
要刪除一個已存在的數據表,可以使用`drop`或`dropIfExists`方法:
~~~
Schema::drop('users');Schema::dropIfExists('users');
~~~
### 5.3 創建列
要更新一個已存在的表,使用Schema門面上的`table`方法,和`create`方法一樣,`table`方法接收兩個參數:表名和獲取用于添加列到表的`Blueprint`實例的閉包:
~~~
Schema::table('users', function ($table) {
$table->string('email');
});
~~~
### 5.3.1 可用的列類型
當然,表結構構建器包含一系列你可以用來構建表的列類型:
| 命令 | 描述 |
| --- | --- |
| `$table->bigIncrements('id');` | 自增ID,類型為bigint |
| `$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');` | 數據庫主鍵自增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`列. |
### 5.3.2 列修改器
除了上面列出的列類型之外,在添加列的時候還可以使用一些其它列”修改器“,例如,要使列默認為null,可以使用`nullable`方法:
~~~
Schema::table('users', function ($table) {
$table->string('email')->nullable();
});
~~~
下面是所有可用的列修改器列表,該列表不包含[索引修改器](http://laravelacademy.org/post/130.html#update-index):
| 修改器 | 描述 |
| --- | --- |
| `->first()` | 將該列置為表中第一個列 (僅適用于MySQL) |
| `->after('column')` | 將該列置于另一個列之后 (僅適用于MySQL) |
| `->nullable()` | 允許該列的值為NULL |
| `->default($value)` | 指定列的默認值 |
| `->unsigned()` | 設置?`integer`?列為?`UNSIGNED` |
### 5.4 修改列
### 5.4.1 先決條件
在修改列之前,確保已經將`doctrine/dbal`依賴添加到`composer.json`文件,Doctrine DBAL庫用于判斷列的當前狀態并在需要時創建SQL查詢來對列進行指定的調整。
### 5.4.2 更新列屬性
`change`方法允許你修改已存在的列為新的類型,或者修改列的屬性。例如,你可能想要增加string類型列的尺寸,讓我們將`name`列的尺寸從25增加到50:
~~~
Schema::table('users', function ($table) {
$table->string('name', 50)->change();
});
~~~
我們還可以修改該列允許NULL值:
~~~
Schema::table('users', function ($table) {
$table->string('name', 50)->nullable()->change();
});
~~~
### 5.4.3 重命名列
要重命名一個列,可以使用表結構構建器上的`renameColumn`方法,在重命名一個列之前,確保`doctrine/dbal`依賴已經添加到`composer.json`文件:
~~~
Schema::table('users', function ($table) {
$table->renameColumn('from', 'to');
});
~~~
> 注意:enum類型的列的重命名暫不支持。
### 5.5 刪除列
要刪除一個列,使用表結構構建器上的`dropColumn`方法:
~~~
Schema::table('users', function ($table) {
$table->dropColumn('votes');
});
~~~
你可以傳遞列名數組到`dropColumn`方法從表中刪除多個列:
~~~
Schema::table('users', function ($table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});
~~~
> 注意:在從SQLite數據庫刪除列之前,需要添加`doctrine/dbal`依賴到`composer.json`文件并在終端中運行`composer update`命令來安裝該庫。
### 5.6 創建索引
表結構構建器支持多種類型的索引,首先,讓我們看一個指定列值為唯一索引的例子。要創建索引,可以使用`unique`方法:
~~~
$table->string('email')->unique();
~~~
此外,你可以在定義列之后創建索引,例如:
~~~
$table->unique('email');
~~~
你甚至可以傳遞列名數組到索引方法來創建混合索引:
~~~
$table->index(['account_id', 'created_at']);
~~~
### 5.6.1 可用索引類型
| 命令 | 描述 |
| --- | --- |
| `$table->primary('id');` | 添加主鍵索引 |
| `$table->primary(['first', 'last']);` | 添加混合索引 |
| `$table->unique('email');` | 添加唯一索引 |
| `$table->index('state');` | 添加普通索引 |
### 5.7 刪除索引
要刪除索引,必須指定索引名。默認情況下,Laravel自動分配適當的名稱給索引——簡單連接表名、列名和索引類型。下面是一些例子:
| 命令 | 描述 |
| --- | --- |
| `$table->dropPrimary('users_id_primary');` | 從?“users”表中刪除主鍵索引 |
| `$table->dropUnique('users_email_unique');` | 從?“users”表中刪除唯一索引 |
| `$table->dropIndex('geo_state_index');` | 從?“geo”表中刪除普通索引 |
### 5.8?外鍵約束
Laravel還提供了創建外鍵約束的支持,用于在數據庫層面強制引用完整性。例如,我們在`posts`表中定義了一個引用`users`表的`id`列的`user_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');
~~~
- 前言
- 序言
- 序言 ―― 發行版本說明
- 序言 ―― 升級指南
- 序言 ―― 貢獻代碼
- 開始
- 開始 ―― 安裝及配置
- 開始 ―― Laravel Homestead
- 基礎
- 基礎 ―― HTTP路由
- 基礎 ―― HTTP 中間件
- 基礎 ―― HTTP 控制器
- 基礎 ―― HTTP 請求
- 基礎 ―― HTTP 響應
- 基礎 ―― 視圖
- 基礎 ―― Blade模板
- 架構
- 架構 ―― 一次請求的生命周期
- 架構 ―― 應用目錄結構
- 架構 ―― 服務提供者
- 架構 ―― 服務容器
- 架構 ―― 契約
- 架構 ―― 門面
- 數據庫
- 數據庫 ―― 起步
- 數據庫 ―― 查詢構建器
- 數據庫 ―― 遷移
- 數據庫 ―― 填充數據
- Eloquent ORM
- Eloquent ORM ―― 起步
- Eloquent ORM ―― 關聯關系
- Eloquent ORM ―― 集合
- Eloquent ORM ―― 調整器
- Eloquent ORM ―― 序列化
- 服務
- 服務 ―― 用戶認證
- 服務 ―― Artisan 控制臺
- 服務 ―― Laravel Cashier(交易)
- 服務 ―― 緩存
- 服務 ―― 集合
- 服務 ―― Laravel Elixir
- 服務 ―― 加密
- 服務 ―― 錯誤&日志
- 服務 ―― 事件
- 服務 ―― 文件系統/云存儲
- 服務 ―― 哈希
- 服務 ―― 幫助函數
- 服務 ―― 本地化
- 服務 ―― 郵件
- 服務 ―― 包開發
- 服務 ―― 分頁
- 服務 ―― 隊列
- 服務 ―― Redis
- 服務 ―― Session
- 服務 ―― Envoy 任務運行器(SSH任務)
- 服務 ―― 任務調度
- 服務 ―― 測試
- 服務 ―― 驗證