跳到內容

資料庫:遷移

簡介

遷移就像您資料庫的版本控制,允許您的團隊定義和分享應用程式的資料庫架構定義。如果您曾經在從原始碼控制拉取您的變更後,必須告訴隊友手動將欄位新增到他們的本機資料庫架構,那麼您就面臨了資料庫遷移所要解決的問題。

Laravel 的 Schema facade 提供對跨 Laravel 所有支援的資料庫系統建立和操作資料表的資料庫不可知支援。通常,遷移會使用此 facade 來建立和修改資料庫資料表和欄位。

產生遷移

您可以使用 make:migration Artisan 命令 來產生資料庫遷移。新的遷移將放置在您的 database/migrations 目錄中。每個遷移檔案名稱都包含一個時間戳記,讓 Laravel 可以判斷遷移的順序。

php artisan make:migration create_flights_table

Laravel 將使用遷移的名稱來嘗試猜測資料表的名稱,以及遷移是否將建立新的資料表。如果 Laravel 能夠從遷移名稱判斷資料表名稱,Laravel 將使用指定的資料表預先填入產生的遷移檔案。否則,您只需在遷移檔案中手動指定資料表即可。

如果您想要為產生的遷移指定自訂路徑,您可以在執行 make:migration 命令時使用 --path 選項。給定的路徑應該相對於您的應用程式基本路徑。

lightbulb

可以使用 stub 發佈 來客製化遷移 stub。

壓縮遷移

當您建構應用程式時,隨著時間的推移,您可能會累積越來越多的遷移。這可能會導致您的 database/migrations 目錄膨脹,其中可能包含數百個遷移。如果您願意,您可以將您的遷移「壓縮」成一個 SQL 檔案。要開始,請執行 schema:dump 命令

php artisan schema:dump
 
# Dump the current database schema and prune all existing migrations...
php artisan schema:dump --prune

當您執行此命令時,Laravel 會將「架構」檔案寫入您應用程式的 database/schema 目錄中。架構檔案的名稱將對應於資料庫連線。現在,當您嘗試遷移您的資料庫且沒有執行其他遷移時,Laravel 將首先執行您正在使用的資料庫連線的架構檔案中的 SQL 陳述式。在執行架構檔案的 SQL 陳述式之後,Laravel 將執行任何未包含在架構傾印中的剩餘遷移。

如果您的應用程式的測試使用與您在本地開發期間通常使用的不同的資料庫連線,您應確保您已使用該資料庫連線傾印架構檔案,以便您的測試能夠建構您的資料庫。您可能希望在傾印您在本地開發期間通常使用的資料庫連線後執行此操作

php artisan schema:dump
php artisan schema:dump --database=testing --prune

您應該將您的資料庫架構檔案提交到原始碼控制,以便您的團隊中其他新的開發人員可以快速建立您應用程式的初始資料庫結構。

exclamation

遷移壓縮僅適用於 MariaDB、MySQL、PostgreSQL 和 SQLite 資料庫,並使用資料庫的命令列用戶端。

遷移結構

遷移類別包含兩個方法:updownup 方法用於在您的資料庫中新增新的資料表、欄位或索引,而 down 方法應該反轉 up 方法執行的操作。

在這兩個方法中,您都可以使用 Laravel 架構建構器來具體地建立和修改資料表。要了解 Schema 建構器上所有可用的方法,請查看其文件。例如,以下遷移會建立 flights 資料表

<?php
 
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
 
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::drop('flights');
}
};

設定遷移連線

如果您的遷移將與您的應用程式預設資料庫連線以外的資料庫連線互動,您應該設定遷移的 $connection 屬性

/**
* The database connection that should be used by the migration.
*
* @var string
*/
protected $connection = 'pgsql';
 
/**
* Run the migrations.
*/
public function up(): void
{
// ...
}

執行遷移

要執行所有您未執行的遷移,請執行 migrate Artisan 命令

php artisan migrate

如果您想要查看目前為止已執行的遷移,您可以使用 migrate:status Artisan 命令

php artisan migrate:status

如果您想要查看遷移將執行的 SQL 陳述式,而實際上不執行它們,您可以向 migrate 命令提供 --pretend 旗標

php artisan migrate --pretend

隔離遷移執行

如果您正在跨多個伺服器部署您的應用程式,並將執行遷移作為您部署過程的一部分,您可能不希望兩個伺服器同時嘗試遷移資料庫。為了避免這種情況,您可以在調用 migrate 命令時使用 isolated 選項。

當提供 isolated 選項時,Laravel 將在使用您應用程式的快取驅動程式嘗試執行遷移之前取得原子鎖定。所有其他在持有該鎖定時嘗試執行 migrate 命令的嘗試將不會執行;但是,該命令仍將以成功的退出狀態碼退出

php artisan migrate --isolated
exclamation

要使用此功能,您的應用程式必須使用 memcachedredisdynamodbdatabasefilearray 快取驅動程式作為您應用程式的預設快取驅動程式。此外,所有伺服器都必須與同一個中央快取伺服器通訊。

強制在生產環境中執行遷移

有些遷移操作具有破壞性,這表示它們可能會導致您遺失資料。為了保護您不會在正式環境資料庫上執行這些指令,在執行指令之前,系統會提示您確認。若要強制執行這些指令而不顯示提示,請使用 --force 旗標。

php artisan migrate --force

回滾遷移

若要回滾最新的遷移操作,您可以使用 rollback Artisan 指令。此指令會回滾最後一個「批次」的遷移,其中可能包含多個遷移檔案。

php artisan migrate:rollback

您可以透過在 rollback 指令中提供 step 選項來回滾有限數量的遷移。例如,以下指令將回滾最後五個遷移。

php artisan migrate:rollback --step=5

您可以透過在 rollback 指令中提供 batch 選項來回滾特定「批次」的遷移,其中 batch 選項對應於應用程式 migrations 資料庫表格中的批次值。例如,以下指令將回滾批次三中的所有遷移。

php artisan migrate:rollback --batch=3

如果您想查看遷移將執行的 SQL 語句,但不實際執行它們,您可以在 migrate:rollback 指令中提供 --pretend 旗標。

php artisan migrate:rollback --pretend

migrate:reset 指令將回滾您應用程式的所有遷移。

php artisan migrate:reset

使用單一指令回滾和遷移

migrate:refresh 指令將回滾您的所有遷移,然後執行 migrate 指令。此指令實際上會重新建立您的整個資料庫。

php artisan migrate:refresh
 
# Refresh the database and run all database seeds...
php artisan migrate:refresh --seed

您可以透過在 refresh 指令中提供 step 選項來回滾和重新遷移有限數量的遷移。例如,以下指令將回滾並重新遷移最後五個遷移。

php artisan migrate:refresh --step=5

刪除所有表格並遷移

migrate:fresh 指令將刪除資料庫中的所有表格,然後執行 migrate 指令。

php artisan migrate:fresh
 
php artisan migrate:fresh --seed

預設情況下,migrate:fresh 指令只會刪除預設資料庫連線中的表格。但是,您可以使用 --database 選項來指定應該遷移的資料庫連線。資料庫連線名稱應與應用程式 database 設定檔 中定義的連線相對應。

php artisan migrate:fresh --database=admin
exclamation

migrate:fresh 指令將刪除所有資料庫表格,無論它們的前綴為何。在與其他應用程式共用的資料庫上開發時,應謹慎使用此指令。

資料表

建立資料表

若要建立新的資料庫表格,請在 Schema facade 上使用 create 方法。create 方法接受兩個引數:第一個是表格的名稱,而第二個是接收 Blueprint 物件的閉包,該物件可用於定義新的表格。

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->timestamps();
});

建立表格時,您可以使用任何 schema builder 的欄位方法來定義表格的欄位。

判斷表格/欄位的存在

您可以使用 hasTablehasColumnhasIndex 方法來判斷表格、欄位或索引是否存在。

if (Schema::hasTable('users')) {
// The "users" table exists...
}
 
if (Schema::hasColumn('users', 'email')) {
// The "users" table exists and has an "email" column...
}
 
if (Schema::hasIndex('users', ['email'], 'unique')) {
// The "users" table exists and has a unique index on the "email" column...
}

資料庫連線和表格選項

如果您想在不是應用程式預設連線的資料庫連線上執行 schema 操作,請使用 connection 方法。

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

此外,還可以使用其他一些屬性和方法來定義表格建立的其他方面。當使用 MariaDB 或 MySQL 時,可以使用 engine 屬性來指定表格的儲存引擎。

Schema::create('users', function (Blueprint $table) {
$table->engine('InnoDB');
 
// ...
});

當使用 MariaDB 或 MySQL 時,可以使用 charsetcollation 屬性來指定所建立表格的字元集和排序規則。

Schema::create('users', function (Blueprint $table) {
$table->charset('utf8mb4');
$table->collation('utf8mb4_unicode_ci');
 
// ...
});

temporary 方法可用於指示表格應為「暫時性」。暫時性表格僅對目前連線的資料庫會話可見,並且在連線關閉時會自動刪除。

Schema::create('calculations', function (Blueprint $table) {
$table->temporary();
 
// ...
});

如果您想在資料庫表格中加入「註解」,您可以在表格實例上呼叫 comment 方法。目前僅 MariaDB、MySQL 和 PostgreSQL 支援表格註解。

Schema::create('calculations', function (Blueprint $table) {
$table->comment('Business calculations');
 
// ...
});

更新資料表

Schema facade 上的 table 方法可用於更新現有的表格。與 create 方法一樣,table 方法接受兩個引數:表格的名稱和接收 Blueprint 實例的閉包,您可以使用該實例來向表格添加欄位或索引。

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});

重新命名 / 刪除資料表

若要重新命名現有的資料庫表格,請使用 rename 方法。

use Illuminate\Support\Facades\Schema;
 
Schema::rename($from, $to);

若要刪除現有的表格,您可以使用 dropdropIfExists 方法。

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

使用外鍵重新命名表格

在重新命名表格之前,您應驗證表格上的任何外鍵約束在您的遷移檔案中都有明確的名稱,而不是讓 Laravel 指定基於約定的名稱。否則,外鍵約束名稱將參考舊的表格名稱。

欄位

建立欄位

Schema facade 上的 table 方法可用於更新現有的表格。與 create 方法一樣,table 方法接受兩個引數:表格的名稱和接收 Illuminate\Database\Schema\Blueprint 實例的閉包,您可以使用該實例來向表格添加欄位。

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});

可用的欄位類型

schema builder blueprint 提供了各種方法,這些方法對應於您可以添加到資料庫表格的不同類型欄位。下表列出了每個可用的方法。

bigIncrements()

bigIncrements 方法會建立一個等同於自動遞增的 UNSIGNED BIGINT (主鍵)欄位。

$table->bigIncrements('id');

bigInteger()

bigInteger 方法會建立一個等同於 BIGINT 的欄位。

$table->bigInteger('votes');

binary()

binary 方法會建立一個等同於 BLOB 的欄位。

$table->binary('photo');

當使用 MySQL、MariaDB 或 SQL Server 時,您可以傳遞 lengthfixed 引數來建立等同於 VARBINARYBINARY 的欄位。

$table->binary('data', length: 16); // VARBINARY(16)
 
$table->binary('data', length: 16, fixed: true); // BINARY(16)

boolean()

boolean 方法會建立一個等同於 BOOLEAN 的欄位。

$table->boolean('confirmed');

char()

char 方法會建立一個指定長度的等同於 CHAR 的欄位。

$table->char('name', length: 100);

dateTimeTz()

dateTimeTz 方法會建立一個等同於 DATETIME (帶時區) 的欄位,並具有可選的小數秒精度。

$table->dateTimeTz('created_at', precision: 0);

dateTime()

dateTime 方法會建立一個等同於 DATETIME 的欄位,並具有可選的小數秒精度。

$table->dateTime('created_at', precision: 0);

date()

date 方法會建立一個等同於 DATE 的欄位。

$table->date('created_at');

decimal()

decimal 方法會建立一個具有指定精度(總位數)和小數位數(小數點後的位數)的等同於 DECIMAL 的欄位。

$table->decimal('amount', total: 8, places: 2);

double()

double 方法會建立一個等同於 DOUBLE 的欄位。

$table->double('amount');

enum()

enum 方法會建立一個具有指定有效值的等同於 ENUM 的欄位。

$table->enum('difficulty', ['easy', 'hard']);

float()

float 方法會建立一個具有指定精度的等同於 FLOAT 的欄位。

$table->float('amount', precision: 53);

foreignId()

foreignId 方法會建立一個等同於 UNSIGNED BIGINT 的欄位。

$table->foreignId('user_id');

foreignIdFor()

foreignIdFor 方法會為給定的模型類別新增一個等同於 {column}_id 的欄位。欄位類型將會是 UNSIGNED BIGINTCHAR(36)CHAR(26),取決於模型鍵類型。

$table->foreignIdFor(User::class);

foreignUlid()

foreignUlid 方法會建立一個等同於 ULID 的欄位。

$table->foreignUlid('user_id');

foreignUuid()

foreignUuid 方法會建立一個等同於 UUID 的欄位。

$table->foreignUuid('user_id');

geography()

geography 方法會建立一個具有指定空間類型和 SRID (空間參考系統識別碼) 的等同於 GEOGRAPHY 的欄位。

$table->geography('coordinates', subtype: 'point', srid: 4326);
lightbulb

對空間類型的支援取決於您的資料庫驅動程式。請參閱資料庫的文件。如果您的應用程式正在使用 PostgreSQL 資料庫,您必須安裝 PostGIS 擴充功能,才能使用 geography 方法。

geometry()

geometry 方法會建立一個具有指定空間類型和 SRID (空間參考系統識別碼) 的等同於 GEOMETRY 的欄位。

$table->geometry('positions', subtype: 'point', srid: 0);
lightbulb

對空間類型的支援取決於您的資料庫驅動程式。請參閱資料庫的文件。如果您的應用程式正在使用 PostgreSQL 資料庫,您必須安裝 PostGIS 擴充功能,才能使用 geometry 方法。

id()

id 方法是 bigIncrements 方法的別名。預設情況下,該方法會建立一個 id 欄位;但是,如果您想為欄位指定不同的名稱,則可以傳遞欄位名稱。

$table->id();

increments()

increments 方法會建立一個自動遞增的等同於 UNSIGNED INTEGER 的欄位作為主鍵。

$table->increments('id');

integer()

integer 方法會建立一個等同於 INTEGER 的欄位。

$table->integer('votes');

ipAddress()

ipAddress 方法會建立一個等同於 VARCHAR 的欄位。

$table->ipAddress('visitor');

當使用 PostgreSQL 時,將會建立一個 INET 欄位。

json()

json 方法會建立一個等同於 JSON 的欄位。

$table->json('options');

jsonb()

jsonb 方法會建立一個等同於 JSONB 的欄位。

$table->jsonb('options');

longText()

longText 方法會建立一個等同於 LONGTEXT 的欄位。

$table->longText('description');

當使用 MySQL 或 MariaDB 時,您可以將 binary 字元集套用到該欄位,以便建立等同於 LONGBLOB 的欄位。

$table->longText('data')->charset('binary'); // LONGBLOB

macAddress()

macAddress 方法會建立一個旨在保留 MAC 位址的欄位。某些資料庫系統 (例如 PostgreSQL) 具有專用於此類型資料的欄位類型。其他資料庫系統將使用等同於字串的欄位。

$table->macAddress('device');

mediumIncrements()

mediumIncrements 方法會建立一個自動遞增的等同於 UNSIGNED MEDIUMINT 的欄位作為主鍵。

$table->mediumIncrements('id');

mediumInteger()

mediumInteger 方法會建立一個等同於 MEDIUMINT 的欄位。

$table->mediumInteger('votes');

mediumText()

mediumText 方法會建立一個等同於 MEDIUMTEXT 的欄位。

$table->mediumText('description');

當使用 MySQL 或 MariaDB 時,您可以將 binary 字元集套用到該欄位,以便建立等同於 MEDIUMBLOB 的欄位。

$table->mediumText('data')->charset('binary'); // MEDIUMBLOB

morphs()

morphs 方法是一種便利方法,它會新增一個等同於 {column}_id 的欄位和一個等同於 {column}_type VARCHAR 的欄位。{column}_id 的欄位類型將會是 UNSIGNED BIGINTCHAR(36)CHAR(26),取決於模型鍵類型。

此方法旨在用於定義多型 Eloquent 關聯所需的欄位。在以下範例中,將會建立 taggable_idtaggable_type 欄位。

$table->morphs('taggable');

nullableTimestamps()

nullableTimestamps 方法是 timestamps 方法的別名。

$table->nullableTimestamps(precision: 0);

nullableMorphs()

此方法與 morphs 方法類似,但建立的欄位將會是「可為空值」。

$table->nullableMorphs('taggable');

nullableUlidMorphs()

此方法與 ulidMorphs 方法類似,但建立的欄位將會是「可為空值」。

$table->nullableUlidMorphs('taggable');

nullableUuidMorphs()

此方法與 uuidMorphs 方法類似,但建立的欄位將會是「可為空值」。

$table->nullableUuidMorphs('taggable');

rememberToken()

rememberToken 方法會建立一個可為空值的 VARCHAR(100) 等效欄位,用於儲存目前的「記住我」身份驗證令牌

$table->rememberToken();

set()

set 方法會建立一個 SET 等效欄位,並具有給定的有效值列表。

$table->set('flavors', ['strawberry', 'vanilla']);

smallIncrements()

smallIncrements 方法會建立一個自動遞增的 UNSIGNED SMALLINT 等效欄位作為主鍵。

$table->smallIncrements('id');

smallInteger()

smallInteger 方法會建立一個 SMALLINT 等效欄位。

$table->smallInteger('votes');

softDeletesTz()

softDeletesTz 方法會新增一個可為空值的 deleted_at TIMESTAMP(帶時區)等效欄位,並可選擇指定秒的小數位數。此欄位旨在儲存 Eloquent 的「軟刪除」功能所需的 deleted_at 時間戳記。

$table->softDeletesTz('deleted_at', precision: 0);

softDeletes()

softDeletes 方法會新增一個可為空值的 deleted_at TIMESTAMP 等效欄位,並可選擇指定秒的小數位數。此欄位旨在儲存 Eloquent 的「軟刪除」功能所需的 deleted_at 時間戳記。

$table->softDeletes('deleted_at', precision: 0);

string()

string 方法會建立一個具有指定長度的 VARCHAR 等效欄位。

$table->string('name', length: 100);

text()

text 方法會建立一個 TEXT 等效欄位。

$table->text('description');

當使用 MySQL 或 MariaDB 時,您可以將 binary 字元集應用於該欄位,以建立 BLOB 等效欄位。

$table->text('data')->charset('binary'); // BLOB

timeTz()

timeTz 方法會建立一個 TIME(帶時區)等效欄位,並可選擇指定秒的小數位數。

$table->timeTz('sunrise', precision: 0);

time()

time 方法會建立一個 TIME 等效欄位,並可選擇指定秒的小數位數。

$table->time('sunrise', precision: 0);

timestampTz()

timestampTz 方法會建立一個 TIMESTAMP(帶時區)等效欄位,並可選擇指定秒的小數位數。

$table->timestampTz('added_at', precision: 0);

timestamp()

timestamp 方法會建立一個 TIMESTAMP 等效欄位,並可選擇指定秒的小數位數。

$table->timestamp('added_at', precision: 0);

timestampsTz()

timestampsTz 方法會建立 created_atupdated_at TIMESTAMP(帶時區)等效欄位,並可選擇指定秒的小數位數。

$table->timestampsTz(precision: 0);

timestamps()

timestamps 方法會建立 created_atupdated_at TIMESTAMP 等效欄位,並可選擇指定秒的小數位數。

$table->timestamps(precision: 0);

tinyIncrements()

tinyIncrements 方法會建立一個自動遞增的 UNSIGNED TINYINT 等效欄位作為主鍵。

$table->tinyIncrements('id');

tinyInteger()

tinyInteger 方法會建立一個 TINYINT 等效欄位。

$table->tinyInteger('votes');

tinyText()

tinyText 方法會建立一個 TINYTEXT 等效欄位。

$table->tinyText('notes');

當使用 MySQL 或 MariaDB 時,您可以將 binary 字元集應用於該欄位,以建立 TINYBLOB 等效欄位。

$table->tinyText('data')->charset('binary'); // TINYBLOB

unsignedBigInteger()

unsignedBigInteger 方法會建立一個 UNSIGNED BIGINT 等效欄位。

$table->unsignedBigInteger('votes');

unsignedInteger()

unsignedInteger 方法會建立一個 UNSIGNED INTEGER 等效欄位。

$table->unsignedInteger('votes');

unsignedMediumInteger()

unsignedMediumInteger 方法會建立一個 UNSIGNED MEDIUMINT 等效欄位。

$table->unsignedMediumInteger('votes');

unsignedSmallInteger()

unsignedSmallInteger 方法會建立一個 UNSIGNED SMALLINT 等效欄位。

$table->unsignedSmallInteger('votes');

unsignedTinyInteger()

unsignedTinyInteger 方法會建立一個 UNSIGNED TINYINT 等效欄位。

$table->unsignedTinyInteger('votes');

ulidMorphs()

ulidMorphs 方法是一個方便的方法,它會新增一個 {column}_id CHAR(26) 等效欄位和一個 {column}_type VARCHAR 等效欄位。

此方法旨在用於定義使用 ULID 識別符的多型 Eloquent 關聯所需的欄位。在以下範例中,將會建立 taggable_idtaggable_type 欄位。

$table->ulidMorphs('taggable');

uuidMorphs()

uuidMorphs 方法是一個方便的方法,它會新增一個 {column}_id CHAR(36) 等效欄位和一個 {column}_type VARCHAR 等效欄位。

此方法旨在用於定義使用 UUID 識別符的多型 Eloquent 關聯所需的欄位。在以下範例中,將會建立 taggable_idtaggable_type 欄位。

$table->uuidMorphs('taggable');

ulid()

ulid 方法會建立一個 ULID 等效欄位。

$table->ulid('id');

uuid()

uuid 方法會建立一個 UUID 等效欄位。

$table->uuid('id');

vector()

vector 方法會建立一個 vector 等效欄位。

$table->vector('embedding', dimensions: 100);

year()

year 方法會建立一個 YEAR 等效欄位。

$table->year('birth_year');

欄位修飾符

除了上面列出的欄位類型之外,您還可以在向資料庫表格新增欄位時使用幾個欄位「修飾符」。例如,若要讓欄位「可為空值」,您可以使用 nullable 方法。

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});

下表包含所有可用的欄位修飾符。此列表不包含索引修飾符

修飾符 描述
->after('column') 將欄位放置在另一個欄位「之後」(MariaDB / MySQL)。
->autoIncrement() INTEGER 欄位設定為自動遞增(主鍵)。
->charset('utf8mb4') 指定欄位的字元集(MariaDB / MySQL)。
->collation('utf8mb4_unicode_ci') 指定欄位的排序規則。
->comment('my comment') 為欄位新增註解(MariaDB / MySQL / PostgreSQL)。
->default($value) 指定欄位的「預設」值。
->first() 將欄位放置在表格的「第一個」位置(MariaDB / MySQL)。
->from($integer) 設定自動遞增欄位的起始值(MariaDB / MySQL / PostgreSQL)。
->invisible() 使欄位在 SELECT * 查詢中「不可見」(MariaDB / MySQL)。
->nullable($value = true) 允許將 NULL 值插入欄位。
->storedAs($expression) 建立儲存的產生欄位(MariaDB / MySQL / PostgreSQL / SQLite)。
->unsigned() INTEGER 欄位設定為 UNSIGNED(MariaDB / MySQL)。
->useCurrent() TIMESTAMP 欄位設定為使用 CURRENT_TIMESTAMP 作為預設值。
->useCurrentOnUpdate() TIMESTAMP 欄位設定為在更新記錄時使用 CURRENT_TIMESTAMP(MariaDB / MySQL)。
->virtualAs($expression) 建立虛擬產生欄位(MariaDB / MySQL / SQLite)。
->generatedAs($expression) 建立具有指定序列選項的身分欄位(PostgreSQL)。
->always() 定義身分欄位序列值相對於輸入的優先順序(PostgreSQL)。

預設運算式

default 修飾符接受一個值或一個 Illuminate\Database\Query\Expression 實例。使用 Expression 實例將會防止 Laravel 將值以引號括起來,並允許您使用資料庫特定的函式。當您需要為 JSON 欄位指派預設值時,這種情況特別有用。

<?php
 
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Migrations\Migration;
 
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->json('movies')->default(new Expression('(JSON_ARRAY())'));
$table->timestamps();
});
}
};
exclamation

對預設運算式的支援取決於您的資料庫驅動程式、資料庫版本和欄位類型。請參閱您的資料庫文件。

欄位順序

當使用 MariaDB 或 MySQL 資料庫時,after 方法可用於在架構中現有欄位之後新增欄位。

$table->after('password', function (Blueprint $table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});

修改欄位

change 方法允許您修改現有欄位的類型和屬性。例如,您可能希望增加 string 欄位的大小。為了展示 change 方法的作用,讓我們將 name 欄位的大小從 25 增加到 50。為了完成此操作,我們只需定義欄位的新狀態,然後呼叫 change 方法。

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

修改欄位時,您必須明確包含您要保留在欄位定義上的所有修飾符 - 任何遺失的屬性都將被刪除。例如,若要保留 unsigneddefaultcomment 屬性,您必須在變更欄位時明確呼叫每個修飾符。

Schema::table('users', function (Blueprint $table) {
$table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
});

change 方法不會變更欄位的索引。因此,您可以在修改欄位時使用索引修飾符來明確新增或刪除索引。

// Add an index...
$table->bigIncrements('id')->primary()->change();
 
// Drop an index...
$table->char('postal_code', 10)->unique(false)->change();

重新命名欄位

若要重新命名欄位,您可以使用架構產生器提供的 renameColumn 方法。

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

刪除欄位

若要刪除欄位,您可以在架構產生器上使用 dropColumn 方法。

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

您可以透過將欄位名稱陣列傳遞給 dropColumn 方法,從表格中刪除多個欄位。

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

可用的命令別名

Laravel 提供了幾個與刪除常見類型欄位相關的便利方法。每個方法都將在下表中說明。

命令 描述
$table->dropMorphs('morphable'); 刪除 morphable_idmorphable_type 欄位。
$table->dropRememberToken(); 刪除 remember_token 欄位。
$table->dropSoftDeletes(); 刪除 deleted_at 欄位。
$table->dropSoftDeletesTz(); dropSoftDeletes() 方法的別名。
$table->dropTimestamps(); 刪除 created_atupdated_at 欄位。
$table->dropTimestampsTz(); dropTimestamps() 方法的別名。

索引

建立索引

Laravel 架構產生器支援幾種索引類型。以下範例會建立一個新的 email 欄位,並指定其值應是唯一的。若要建立索引,我們可以將 unique 方法鏈接到欄位定義。

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});

或者,您可以在定義欄位後建立索引。若要執行此操作,您應該在架構產生器藍圖上呼叫 unique 方法。此方法接受應接收唯一索引的欄位名稱。

$table->unique('email');

您甚至可以將欄位陣列傳遞給索引方法以建立複合(或組合)索引。

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

當建立索引時,Laravel 會根據資料表、欄位名稱和索引類型自動產生索引名稱,但您可以將第二個參數傳遞給方法來自行指定索引名稱

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

可用的索引類型

Laravel 的 Schema Builder Blueprint 類別提供了建立 Laravel 支援的每一種索引類型的方法。每個索引方法都接受一個可選的第二個參數,以指定索引的名稱。如果省略,名稱將從資料表和用於索引的欄位名稱以及索引類型衍生而來。下表描述了每個可用的索引方法

命令 描述
$table->primary('id'); 新增一個主鍵。
$table->primary(['id', 'parent_id']); 新增複合鍵。
$table->unique('email'); 新增唯一索引。
$table->index('state'); 新增一個索引。
$table->fullText('body'); 新增全文索引 (MariaDB / MySQL / PostgreSQL)。
$table->fullText('body')->language('english'); 新增指定語言的全文索引 (PostgreSQL)。
$table->spatialIndex('location'); 新增空間索引 (SQLite 除外)。

重新命名索引

要重新命名索引,您可以使用 Schema Builder Blueprint 提供的 renameIndex 方法。此方法接受目前的索引名稱作為其第一個參數,並將所需的名稱作為其第二個參數

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

刪除索引

要刪除索引,您必須指定索引的名稱。預設情況下,Laravel 會根據資料表名稱、索引欄位的名稱和索引類型自動指定索引名稱。以下是一些範例

命令 描述
$table->dropPrimary('users_id_primary'); 從 "users" 資料表中刪除主鍵。
$table->dropUnique('users_email_unique'); 從 "users" 資料表中刪除唯一索引。
$table->dropIndex('geo_state_index'); 從 "geo" 資料表中刪除基本索引。
$table->dropFullText('posts_body_fulltext'); 從 "posts" 資料表中刪除全文索引。
$table->dropSpatialIndex('geo_location_spatialindex'); 從 "geo" 資料表中刪除空間索引 (SQLite 除外)。

如果您將欄位陣列傳遞給刪除索引的方法,將會根據資料表名稱、欄位和索引類型產生慣用的索引名稱

Schema::table('geo', function (Blueprint $table) {
$table->dropIndex(['state']); // Drops index 'geo_state_index'
});

外鍵約束

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

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
 
$table->foreign('user_id')->references('id')->on('users');
});

由於此語法相當冗長,Laravel 提供了額外的、更簡潔的方法,這些方法使用慣例來提供更好的開發人員體驗。當使用 foreignId 方法建立您的欄位時,上面的範例可以改寫如下

Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained();
});

foreignId 方法建立一個等效的 UNSIGNED BIGINT 欄位,而 constrained 方法將使用慣例來判斷正在參照的資料表和欄位。如果您的資料表名稱與 Laravel 的慣例不符,您可以手動將其提供給 constrained 方法。此外,也可以指定應該指派給所產生索引的名稱

Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained(
table: 'users', indexName: 'posts_user_id'
);
});

您也可以為約束的 "on delete" 和 "on update" 屬性指定所需的操作

$table->foreignId('user_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');

這些操作也提供了另一種具表達性的語法

方法 描述
$table->cascadeOnUpdate(); 更新應級聯。
$table->restrictOnUpdate(); 更新應受限制。
$table->nullOnUpdate(); 更新應將外鍵值設定為 null。
$table->noActionOnUpdate(); 更新時不採取任何動作。
$table->cascadeOnDelete(); 刪除應級聯。
$table->restrictOnDelete(); 刪除應受限制。
$table->nullOnDelete(); 刪除應將外鍵值設定為 null。
$table->noActionOnDelete(); 如果存在子記錄,則防止刪除。

任何額外的 欄位修飾符 都必須在 constrained 方法之前呼叫

$table->foreignId('user_id')
->nullable()
->constrained();

刪除外鍵

要刪除外鍵,您可以使用 dropForeign 方法,將要刪除的外鍵約束名稱作為參數傳遞。外鍵約束使用與索引相同的命名慣例。換句話說,外鍵約束名稱基於資料表的名稱和約束中的欄位,後接 "_foreign" 後綴

$table->dropForeign('posts_user_id_foreign');

或者,您可以將包含保存外鍵的欄位名稱的陣列傳遞給 dropForeign 方法。該陣列將使用 Laravel 的約束命名慣例轉換為外鍵約束名稱

$table->dropForeign(['user_id']);

切換外鍵約束

您可以使用以下方法在遷移中啟用或停用外鍵約束

Schema::enableForeignKeyConstraints();
 
Schema::disableForeignKeyConstraints();
 
Schema::withoutForeignKeyConstraints(function () {
// Constraints disabled within this closure...
});
exclamation

SQLite 預設停用外鍵約束。當使用 SQLite 時,請確保在嘗試在遷移中建立外鍵約束之前,在資料庫組態中啟用外鍵支援

事件

為了方便起見,每個遷移操作都會分派一個事件。以下所有事件都擴充了基本 Illuminate\Database\Events\MigrationEvent 類別

類別 描述
Illuminate\Database\Events\MigrationsStarted 即將執行一批遷移。
Illuminate\Database\Events\MigrationsEnded 一批遷移已執行完成。
Illuminate\Database\Events\MigrationStarted 即將執行單個遷移。
Illuminate\Database\Events\MigrationEnded 單個遷移已執行完成。
Illuminate\Database\Events\NoPendingMigrations 遷移命令未找到待處理的遷移。
Illuminate\Database\Events\SchemaDumped 資料庫結構描述轉儲已完成。
Illuminate\Database\Events\SchemaLoaded 已載入現有的資料庫結構描述轉儲。