資料庫遷移


    ##資料庫:遷移
  • 簡介
  • #產生遷移
    • 遷移結構
    執行遷移
  • #回滾遷移
    • 資料表
    • 建立資料表
    • # 重新命名/ 刪除資料表
  • 字段
    • 建立字段
    • #字段修飾
    • 修改字段
    • 刪除欄位
#索引

建立索引

重新命名索引

#刪除索引

#外鍵約束

#########################簡介#######遷移就像是資料庫的版本控制,允許團隊簡單輕鬆的編輯並共享應用的資料庫表結構,遷移通常和Laravel 的資料庫結構產生器配合使用,讓你輕鬆建構資料庫結構。如果你曾經試過讓同事手動在資料庫結構中添加字段,那麼資料庫遷移可以讓你不再需要做這樣的事情。 ######Laravel 的 ###Schema### 門面 對所有 Laravel 支援的資料庫系統提供了建立和操作資料表的相應支援。 #####################

產生遷移

使用 Artisan 指令 make:migration 來建立遷移。

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 個方法: updown up 方法用來新增新的資料表, 欄位或索引到資料庫,而 down# 方法就是up 方法的反操作,而 up 裡的操作相反。

在這2 個方法中都要用到Laravel 的Schema 建構器來建立和修改表,
若要了解Schema 生成器中的所有可用方法,可以查看它的文件。例如,建立flights 表的簡單範例:

<?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');   
      }
 }

#運行遷移

執行Artisan指令migrate 來執行所有未完成的遷移:

php artisan migrate

#{注意} 如果你正在使用Homestead 虛擬機,你應該在你的虛擬機裡執行這個指令。

在生產環境強制執行遷移

某些遷移作業是具有破壞性的, 這表示可能會導致資料遺失。為了防止有人在生產環境中運行這些命令, 系統會在這些命令被運行之前與你進行確認。如果要強制忽略系統的提示執行指令,則可以使用 --force 標記:

php artisan migrate --force

##回滾遷移

若要回滾最後一次遷移, 可以使用

rollback 指令。此指令會回滾最後一次「遷移」 的操作,其中可能包含多個遷移檔:

php artisan migrate:rollback

你可以在

rollback 指令後面加上step 參數,來限制回滾遷移的個數。例如,以下指令將回滾最近五次遷移:

php artisan migrate:rollback --step=5

migrate:reset 指令可以回滾應用程式中的所有遷移:

php artisan migrate:reset

#

使用單一指令來執行回滾或遷移

migrate:refresh 指令不僅會回滾資料庫的所有遷移還會接著執行 migrate 指令。這個指令可以有效率地重建整個資料庫:

php artisan migrate:refresh
// 刷新数据库结构并执行数据填充
php artisan migrate:refresh --seed

使用 refresh 指令並提供 step 參數來回滾來並再執行最後指定的遷移數。例如, 下列指令會回滾並重新執行最後五次遷移:

php artisan migrate:refresh --step=5

刪除所有表& 遷移

The migrate:fresh 指令會從資料庫中刪除所有表,然後執行migrate  指令:

php artisan migrate:fresh

php artisan migrate:fresh --seed

##資料表

建立資料表

可以使用 

Schema facade 的 create 方法來創建新的資料庫表。 create 方法接受兩個參數:第一個參數為資料表的名稱,第二個參數是 Closure ,此閉包會接收一個用於定義新資料表的 Blueprint 物件:

Schema::create('users', function (Blueprint $table) 
{   
 $table->increments('id');
});

當然,在建立資料表的時候,可以使用任何資料庫結構產生器的

欄位方法 來定義資料表的欄位。

檢查資料表/ 欄位是否存在

可以使用

hasTablehasColumn 方法來檢查資料表或欄位是否存在:

if (Schema::hasTable('users')) { 
   //
   }
if (Schema::hasColumn('users', 'email')) { 
      //
    }

#

資料庫連線& 表格選項

如果要對非預設連線的資料庫連線執行結構操作,可以使用connection 方法:

Schema::connection('foo')->create('users', function (Blueprint $table) { 
   $table->increments('id');
  });

你可以在資料庫結構生成器上使用以下指令來定義表格的選項:

##$table->engine = 'InnoDB';指定表格儲存引擎(MySQL)。 $table->charset = 'utf8';指定資料表的預設字元集 (MySQL)。 $table->collat​​ion = 'utf8_unicode_ci';指定資料表預設的排序規則 (MySQL)。
指令描述
#########$table->temporary();##########建立暫存資料表 (不支援 SQL Server)。 ############

重新命名/ 刪除資料表

若要重新命名資料表,可以使用rename 方法:

Schema::rename($from, $to);

刪除一個已存在的資料表, 可使用 dropdropIfExists 方法:

Schema::drop('users');Schema::dropIfExists('users');

# 重新命名帶外鍵的資料表

在重新命名表之前,你應該驗證表上的任何外鍵約束在遷移檔案中都有明確的名稱,而不是讓Laravel 依照約定來設定名稱。否則,外鍵的約束名稱將引用舊表名。

#創建欄位

使用Schema facade 的table 方法可以更新現有的資料表。如同create 方法一樣,table 方法會接受兩個參數:一個是資料表的名稱,另一個則是接收可以用來新增欄位的Blueprint 實例的閉包:

Schema::table('users', function (Blueprint $table) { 
   $table->string('email');
  });

可用的欄位類型

資料庫結構產生器包含在建構表時可以指定的各種欄位類型:

相當於DATE相當於DATETIME #相當於帶時區DATETIME$table->double('amount', 8, 2);$table->enum('level', ['easy', 'hard']);$table->float('amount', 8, 2);相當於GEOMETRYCOLLECTION遞增的ID (主鍵),相當於「UNSIGNED INTEGER」相當於INTEGER相當於IP 位址等於JSON相當於JSONB相當於LINESTRING#相當於LONGTEXT相當於MAC 位址#遞增ID (主鍵) ,相當於「UNSIGNED MEDIUM INTEGER」#相當於MEDIUMINT相當於MEDIUMTEXT
指令描述
#$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');
$table->dateTime('created_at ');
#$table->dateTimeTz('created_at');
$table->decimal('amount', 8, 2);##相當於帶有精確度與基底數DECIMAL
##相當於帶有精確度與基數DOUBLE
相當於ENUM
相當於帶有精確度與基數FLOAT
$table->geometry('positions');#相當於GEOMETRY
##$table ->geometryCollection('positions');
$table->increments('id');
$table->integer('votes');
$table->ipAddress('visitor');
$table->json('options');
$table->jsonb('options');
$table->lineString( 'positions');
#$table->longText('description');
$table->macAddress('device');
$table->mediumIncrements('id');
$table->mediumInteger('votes');
$ table->mediumText('description');
$table->morphs('taggable');等於加入遞增的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_atupdated_at TIMESTAMP
$table->timestampsTz();#相當於可空且帶有時區的created_atupdated_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############

欄位修飾

除了上述列出的欄位類型之外,還有幾個可以在新增欄位到資料庫表格時使用的 「修飾符」。例如,如果要把欄位設為 「可空 ", 你可以使用  nullable 方法:

Schema::table('users', function (Blueprint $table) {
    $table->string('email')->nullable();
 });

以下是所有可用的欄位修飾符的清單。此清單不包括 索引修飾符

##指定字元集(MySQL)指定資料列的排序規則(MySQL/SQL Server)#為欄位增加註解(MySQL)為欄位指定"預設" 值##->first()#->nullable($value = true)#->storedAs($expression)->unsigned()->useCurrent()#->virtualAs($expression)

修改欄位

#先決條件

在修改欄位之前,請確保將doctrine/dbal 依賴關係加入到composer.json  檔案中。 Doctrine DBAL 函式庫用於決定欄位的目前狀態,並建立對該欄位進行指定調整所需的SQL 查詢:

composer require doctrine/dbal

更新欄位屬性

change 方法可以將現有的欄位類型修改為新的類型或修改屬性。
比如,你可能想增加。字串欄位的長度,可以用change 方法把 name 欄位的長度從25 增加到50:

 Schema::table('users', function (Blueprint $table) { 
    $table->string('name', 50)->change(); 
  });

我們應該將欄位修改為可空:

Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->nullable()->change();
  });

{註} 只有下面的欄位類型能被"修改": bigInteger、 binary、 boolean、date、dateTime、dateTimeTz、decimal、integer、json、 longText、mediumText、smallInteger、string、text 、time、 unsignedBigInteger、unsignedInteger and unsignedSmallInteger。

重命名欄位

可以使用結構產生器上的 renameColumn 方法來重新命名欄位。在重新命名欄位前, 請確保你的composer.json 檔案內已經加入 doctrine/dbal 依賴:

Schema::table('users', function (Blueprint $table) {
    $table->renameColumn('from', 'to');
 });

{註} 目前不支援enum 類型的欄位重新命名。

刪除欄位

可以使用結構產生器上的dropColumn 方法來刪除字段。在從SQLite 資料庫刪除欄位前,你需要在composer.json 檔案中加入 doctrine/dbal 依賴並在終端執行composer update 來安裝該依賴:

Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('votes');
 });

你可以傳遞一個字段數組給dropColumn 方法來刪除多個字段:

Schema::table('users', function (Blueprint $table) {  
  $table->dropColumn(['votes', 'avatar', 'location']);
});

{注} 不支援在使用SQLite 資料庫時在單個遷移中刪除或修改多個欄位。

可用的指令別名

ModifierDescription
->after('column') 將此欄位放置在其它欄位"之後" (MySQL)
->autoIncrement()#將INTEGER 類型的欄位設定為自動遞增的主鍵
#->charset('utf8')
->collat​​ion('utf8_unicode_ci')
->comment('my comment')
->default($value)
將此欄位放置在資料表的"首位" (MySQL)
此欄位允許寫入NULL 值(預設)
##創建一個儲存產生的欄位(MySQL)
設定INTEGER 類型的欄位為UNSIGNED (MySQL)
#將TIMESTAMP 類型的欄位設定為使用CURRENT_TIMESTAMP 作為預設值
建立一個虛擬產生的欄位(MySQL)
$table->dropTimestamps(); and
CommandDescription
Description
$table->dropRememberToken();刪除remember_token 欄位。
$table->dropSoftDeletes();刪除  deleted_at 欄位。
$table->dropSoftDeletesTz();dropSoftDeletes() 方法的別名。
##刪除created_atupdated_at 字段。
$table->dropTimestampsTz();############dropTimestamps()### 方法的別名。 ############

索引

建立索引

結構產生器支援多種類型的索引。首先,先指定欄位值唯一,即簡單地在欄位定義之後鍊式呼叫 unique 方法來建立索引,例如:

$table->string('email')->unique();

或者,你也可以在定義完欄位之後建立索引。例如:

$table->unique('email');

你甚至可以將陣列傳遞給索引方法來建立一個複合(或合成)索引:

$table->index(['account_id', 'created_at']);

Laravel 會自動產生一個合理的索引名稱,但你也可以傳遞第二個參數來自訂索引名稱:

$table->unique('email', 'unique_email');

可用的索引類型

每個索引方法都接受一個可選的第二個參數來指定索引的名稱。如果省略,名稱將根據表格和列的名稱產生。

##新增普通索引#新增空間索引(不支援SQLite)

索引長度 & Mysql / MariaDB

Laravel 預設使用 utf8mb4 編碼,它支援在資料庫中儲存 emojis 。如果你是在版本低於 5.7.7 的 MySQL 或版本低於 10.2.2 的 MariaDB 上建立索引,那你就需要手動設定資料庫遷移的預設字串長度。
即在AppServiceProvider 中呼叫Schema::defaultStringLength 方法來設定它:

use Illuminate\Support\Facades\Schema;
/**
 * 引导任何应用程序服务
 *
 * @return void
 */ 
public function boot() {  
   Schema::defaultStringLength(191);
  }

當然,你也可以選擇開啟資料庫的innodb_large_prefix 選項。至於如何正確開啟,請自行查閱資料庫文件。

重新命名索引

#若要重新命名索引,你需要呼叫renameIndex 方法。此方法接受目前索引名稱作為其第一個參數,並將所需名稱作為其第二個參數:
你需要將目前索引名稱作為其第一個參數,並將新索引名稱作為其第二參數:

$table->renameIndex('from', 'to')

刪除索引

若要刪除索引,則必須指定索引的名稱。 Laravel 預設會自動將資料庫名稱、索引的欄位名稱及索引類型簡單地連接在一起作為名稱。舉例如下:

指令描述
#$table->primary ('id');新增主鍵
#$table->primary(['id', 'parent_id']); 新增複合鍵
$table->unique('email');新增唯一索引
$table->index('state');
$table->spatialIndex('location');
指令描述
$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' 索引
   });

外鍵約束

Laravel 也支援建立用於在資料庫層中的強制參考完整性的外鍵約束。例如,讓我們在posts 表上定義一個引用users 表格的id 欄位的user_id 欄位:

Schema::table('posts', function (Blueprint $table) {
    $table->unsignedInteger('user_id');    
    $table->foreign('user_id')->references('id')->on('users');
 });

也可以為on deleteon 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 時,請確保在資料庫設定中啟用 [啟用外鍵支援](/docs/laravel/5.8 /database#configuration),然後再嘗試在遷移中建立它們。

本篇首發在 LearnKu.com 網站上。