[TOC]
### **1、簡介**
[遷移](http://laravelacademy.org/tags/%e8%bf%81%e7%a7%bb "View all posts in 遷移")就像[數據庫](http://laravelacademy.org/tags/%e6%95%b0%e6%8d%ae%e5%ba%93 "View all posts in 數據庫")的版本控制,允許團隊簡單輕松的編輯并共享應用的數據庫表結構,遷移通常和?[Laravel](http://laravelacademy.org/tags/laravel "View all posts in Laravel")?的結構構建器結對從而可以很容易地構建應用的數據庫表結構。
Laravel 的`Schema`門面提供了與數據庫系統無關的[創建](http://laravelacademy.org/tags/%e5%88%9b%e5%bb%ba "View all posts in 創建")和操縱表的支持,在 Laravel 所支持的所有數據庫系統中提供一致的、優雅的、平滑的API。
### **2、生成遷移**
使用 Artisan 命令`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`方法用于新增表,列或者[索引](http://laravelacademy.org/tags/%e7%b4%a2%e5%bc%95 "View all posts in 索引")到數據庫,而`down`方法就是`up`方法的反操作,和`up`里的操作相反。
在這兩個方法中你都要用到 Laravel 的表結構構建器來創建和修改表,例如,讓我們先看看創建`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/2749.html),應該在你的虛擬機中運行如下這條命令:
~~~
php artisan migrate
~~~
如果再運行時遇到“class not found”的錯誤提示,嘗試運行`composer dump-autoload`命令然后重新運行遷移命令。
**在生產環境中強制運行遷移**
有些遷移操作是毀滅性的,這意味著它們可能造成數據的丟失,為了避免在生產環境數據庫中運行這些命令,你將會在運行這些命令之前被提示并確認。想要強制運行這些命令而不被提示,可以使用`--force`:
~~~
php artisan migrate --force
~~~
#### **[回滾](http://laravelacademy.org/tags/%e5%9b%9e%e6%bb%9a "View all posts in 回滾")遷移**
想要回滾最新的一次遷移”操作“,可以使用`rollback`命令,注意這將會回滾最后一批運行的遷移,可能包含多個遷移文件:
~~~
php artisan migrate:rollback
~~~
`migrate:reset`命令將會回滾所有的應用遷移:
~~~
php artisan migrate:reset
~~~
**在單個命令中回滾/遷移**
`migrate:refresh`命令將會先回滾所有數據庫遷移,然后運行`migrate`命令。這個命令可以有效的重建整個數據庫:
~~~
php artisan migrate:refresh
php artisan migrate:refresh --seed
~~~
### **5、編寫遷移**
#### **創建表**
使用`Schema`門面上的`create`方法來創建新的數據表。`create`方法接收兩個參數,第一個是表名,第二個是獲取用于定義新表的`Blueprint`對象的閉包:
~~~
Schema::create('users', function ($table) {
$table->increments('id');
});
~~~
當然,創建新表的時候,可以使用表結構構建器中的任意列方法來定義數據表的列。
**檢查表/列是否存在**
你可以輕松地使用?`hasTable`?和?`hasColumn`?方法檢查表或列是否存在:
~~~
if (Schema::hasTable('users')) {
//
}
if (Schema::hasColumn('users', 'email')) {
//
}
~~~
**連接&[存儲引擎](http://laravelacademy.org/tags/%e5%ad%98%e5%82%a8%e5%bc%95%e6%93%8e "View all posts in 存儲引擎")**
如果你想要在一個數據庫連接上執行表結構操作,該數據庫連接并不是默認數據庫連接,使用`connection`方法:
~~~
Schema::connection('foo')->create('users', function ($table) {
$table->increments('id');
});
~~~
要設置表的存儲引擎,在表結構構建器上設置`engine`屬性:
~~~
Schema::create('users', function ($table) {
$table->engine = 'InnoDB';
$table->increments('id');
});
~~~
#### **[重命名](http://laravelacademy.org/tags/%e9%87%8d%e5%91%bd%e5%90%8d "View all posts in 重命名")/[刪除](http://laravelacademy.org/tags/%e5%88%a0%e9%99%a4 "View all posts in 刪除")表**
要重命名一個已存在的數據表,使用`rename`方法:
~~~
Schema::rename($from, $to);
~~~
要刪除一個已存在的數據表,可以使用`drop`或`dropIfExists`方法:
~~~
Schema::drop('users');
Schema::dropIfExists('users');
~~~
#### **創建列**
要更新一個已存在的表,使用Schema門面上的`table`方法,和`create`方法一樣,`table`方法接收兩個參數:表名和獲取用于添加列到表的`Blueprint`實例的閉包:
~~~
Schema::table('users', function ($table) {
$table->string('email');
});
~~~
**可用的列類型**
當然,表結構構建器包含一系列你可以用來構建表的列類型:
| 命令 | 描述 |
| --- | --- |
| `$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`列. |
| `$table->uuid('id');` | 等同于數據庫的UUID |
#### **列修改器**
除了上面列出的列類型之外,在添加列的時候還可以使用一些其它列“修改器”,例如,要使列默認為`null`,可以使用`nullable`方法:
~~~
Schema::table('users', function ($table) {
$table->string('email')->nullable();
});
~~~
下面是所有可用的列修改器列表,該列表不包含索引修改器:
| 修改器 | 描述 |
| --- | --- |
| `->first()` | 將該列置為表中第一個列 (僅適用于MySQL) |
| `->after('column')` | 將該列置于另一個列之后 (僅適用于MySQL) |
| `->nullable()` | 允許該列的值為NULL |
| `->default($value)` | 指定列的默認值 |
| `->unsigned()` | 設置?`integer`?列為?`UNSIGNED` |
#### **修改列**
**先決條件**
在修改列之前,確保已經將`doctrine/dbal`依賴添加到`composer.json`文件,Doctrine DBAL 庫用于判斷列的當前狀態并在需要時創建SQL查詢來對列進行指定的調整。
**更新列屬性**
`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();
});
~~~
**重命名列**
要重命名一個列,可以使用表結構構建器上的`renameColumn`方法,在重命名一個列之前,確保`doctrine/dbal`依賴已經添加到`composer.json`文件:
~~~
Schema::table('users', function ($table) {
$table->renameColumn('from', 'to');
});
~~~
> 注意:暫不支持 enum類型的列的重命名。
#### **刪除列**
要刪除一個列,使用表結構構建器上的`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`命令來安裝該庫。此外,SQLite數據庫暫不支持在單個遷移中刪除或修改多個列。
#### **創建索引**
表結構構建器支持多種類型的索引,首先,讓我們看一個指定列值為唯一索引的例子。要創建索引,可以使用`unique`方法:
~~~
$table->string('email')->unique();
~~~
此外,你可以在定義列之后創建索引,例如:
~~~
$table->unique('email');
~~~
你甚至可以傳遞列名數組到索引方法來創建組合索引:
~~~
$table->index(['account_id',?'created_at']);
~~~
Laravel 會自動生成合理的索引名稱,但是你可以傳遞第二個參數到該方法用于指定索引名稱:
~~~
$table->index('email',?'my_index_name');
~~~
**可用索引類型**
| 命令 | 描述 |
| --- | --- |
| `$table->primary('id');` | 添加主鍵索引 |
| `$table->primary(['first', 'last']);` | 添加混合索引 |
| `$table->unique('email');` | 添加唯一索引 |
| `$table->unique('state',?'my_index_name');` | 指定自定義索引名稱 |
| `$table->index('state');` | 添加普通索引 |
#### **刪除索引**
要刪除索引,必須指定索引名。默認情況下,Laravel 自動分配適當的名稱給索引——簡單連接表名、列名和索引類型。下面是一些例子:
| 命令 | 描述 |
| --- | --- |
| `$table->dropPrimary('users_id_primary');` | 從?“users”表中刪除主鍵索引 |
| `$table->dropUnique('users_email_unique');` | 從?“users”表中刪除唯一索引 |
| `$table->dropIndex('geo_state_index');` | 從?“geo”表中刪除普通索引 |
#### **[外鍵](http://laravelacademy.org/tags/%e5%a4%96%e9%94%ae "View all posts in 外鍵")約束**
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 模板引擎
- 架構
- 一次請求的生命周期
- 應用目錄結構
- 服務提供者
- 服務容器
- 門面(Facades)
- 數據庫
- 起步
- 查詢構建器
- 遷移
- 填充數據
- Eloquent ORM
- 起步
- 關聯關系
- 集合
- 訪問器&修改器
- 序列化
- 服務
- 用戶認證
- 用戶授權
- Artisan Console
- 訂閱支付實現:Laravel Cashier
- 緩存
- 集合
- 集成前端資源:Laravel Elixir
- 加密
- 錯誤&日志
- 事件
- 文件系統/云存儲
- 哈希
- 輔助函數
- 本地化
- 郵件
- 包開發
- 分頁
- Redis
- 隊列
- Session
- Envoy Task Runner
- 任務調度
- 測試
- 驗證
- 新手入門指南
- 簡單任務管理系統
- 帶用戶功能的任務管理系統