資料庫:遷移
簡介
遷移就像您資料庫的版本控制,允許您的團隊定義並共享應用程式的資料庫結構定義。如果您曾經在從版本控制拉取變更後,不得不告訴隊友手動在他們本地資料庫結構定義中新增一個資料欄,那麼您就已經面臨過資料庫遷移所解決的問題。
Laravel Schema
外觀為所有 Laravel 支援的資料庫系統提供了與資料庫無關的支援,用於建立和操作資料表。通常,遷移會使用此外觀來建立和修改資料庫資料表和資料欄。
生成遷移
您可以使用 make:migration
Artisan 指令來生成資料庫遷移。新的遷移將會放置在您的 database/migrations
目錄中。每個遷移檔案名稱都包含一個時間戳記,允許 Laravel 判斷遷移的順序:
php artisan make:migration create_flights_table
Laravel 會使用遷移的名稱來嘗試猜測資料表的名稱,以及該遷移是否會建立一個新的資料表。如果 Laravel 能夠從遷移名稱中確定資料表名稱,Laravel 會使用指定的資料表預填生成的遷移檔案。否則,您可以手動在遷移檔案中指定資料表。
如果您想為生成的遷移指定一個自訂路徑,可以在執行 make:migration
指令時使用 --path
選項。給定的路徑應相對於您的應用程式基礎路徑。
📌 備註
遷移 stub 可透過 stub publishing 進行客製化。
壓縮遷移
隨著您建立應用程式,您可能會隨著時間累積越來越多的遷移。這可能導致您的 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
您應該將您的資料庫結構定義檔案提交到版本控制,以便團隊中的其他新開發人員可以快速建立應用程式的初始資料庫結構。
⚠️ 警告
遷移壓縮僅適用於 MariaDB、MySQL、PostgreSQL 和 SQLite 資料庫,並利用資料庫的命令列用戶端。
遷移結構
一個遷移類別包含兩個方法:up
和 down
。up
方法用於向您的資料庫新增資料表、資料欄或索引,而 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
{
// ...
}
跳過遷移
有時,某個遷移可能旨在支援尚未啟用的功能,而您不希望它立即執行。在這種情況下,您可以在遷移上定義一個 shouldRun
方法。如果 shouldRun
方法回傳 false
,則該遷移將被跳過:
use App\Models\Flights;
use Laravel\Pennant\Feature;
/**
* Determine if this migration should run.
*/
public function shouldRun(): bool
{
return Feature::active(Flights::class);
}
執行遷移
若要執行所有尚未執行的遷移,請執行 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
⚠️ 警告
若要利用此功能,您的應用程式必須使用 memcached
、redis
、dynamodb
、database
、file
或 array
快取驅動作為您的應用程式的預設快取驅動。此外,所有伺服器都必須與相同的中央快取伺服器通訊。
強制遷移在正式環境中執行
某些遷移操作是破壞性的,這表示它們可能會導致您遺失資料。為了保護您免於在正式資料庫上執行這些命令,在命令執行前會提示您進行確認。若要強制執行命令而無需提示,請使用 --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
⚠️ 警告
migrate:fresh
命令將無論其前綴如何,都會刪除所有資料庫資料表。在與其他應用程式共享的資料庫上進行開發時,應謹慎使用此命令。
資料表
建立資料表
要建立新的資料庫資料表,請使用 Schema
Facade 上的 create
方法。create
方法接受兩個引數:第一個是資料表的名稱,第二個是一個閉包 (closure),此閉包會收到一個 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 的任何資料欄方法來定義資料表的資料欄。
判斷資料表 / 資料欄是否存在
您可以使用 hasTable
、hasColumn
和 hasIndex
方法來判斷資料表、資料欄或索引是否存在:
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 時,charset
和 collation
屬性可用於指定所建立資料表的字元集和定序:
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);
要刪除現有的資料表,您可以使用 drop
或 dropIfExists
方法:
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) 提供了多種方法,對應可添加到資料庫資料表中的各種資料欄類型。下表列出了所有可用的方法:
布林類型
字串與文字類型
數值類型
bigIncrementsbigIntegerdecimaldoublefloatidincrementsintegermediumIncrementsmediumIntegersmallIncrementssmallIntegertinyIncrementstinyIntegerunsignedBigIntegerunsignedIntegerunsignedMediumIntegerunsignedSmallIntegerunsignedTinyInteger
日期與時間類型
二進位類型
物件與 JSON 類型
UUID 與 ULID 類型
空間類型
關聯類型
特殊類型
bigIncrements()
bigIncrements
方法會建立一個自動遞增的 UNSIGNED BIGINT
(主鍵) 等效資料欄:
$table->bigIncrements('id');
bigInteger()
bigInteger
方法會建立一個 BIGINT
等效資料欄:
$table->bigInteger('votes');
binary()
binary
方法會建立一個 BLOB
等效資料欄:
$table->binary('photo');
當使用 MySQL、MariaDB 或 SQL Server 時,您可以傳遞 length
和 fixed
引數以建立 VARBINARY
或 BINARY
等效資料欄:
$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
等效資料欄,具有指定的總位數 (precision) 和小數位數 (scale):
$table->decimal('amount', total: 8, places: 2);
double()
double
方法會建立一個 DOUBLE
等效資料欄:
$table->double('amount');
enum()
enum
方法會建立一個 ENUM
等效資料欄,具有指定的有效值:
$table->enum('difficulty', ['easy', 'hard']);
當然,你可以使用 Enum::cases()
方法,而不是手動定義允許值的陣列:
use App\Enums\Difficulty;
$table->enum('difficulty', Difficulty::cases());
float()
float
方法會建立一個 FLOAT
等效資料欄,具有指定的精確度:
$table->float('amount', precision: 53);
foreignId()
foreignId
方法會建立一個 UNSIGNED BIGINT
等效資料欄:
$table->foreignId('user_id');
foreignIdFor()
foreignIdFor
方法會為給定的模型類別增加一個 {column}_id
等效資料欄。此資料欄的類型將根據模型鍵的類型而定,可以是 UNSIGNED BIGINT
、CHAR(36)
或 CHAR(26)
:
$table->foreignIdFor(User::class);
foreignUlid()
foreignUlid
方法會建立一個 ULID
等效資料欄:
$table->foreignUlid('user_id');
foreignUuid()
foreignUuid
方法會建立一個 UUID
等效資料欄:
$table->foreignUuid('user_id');
geography()
geography
方法會建立一個 GEOGRAPHY
等效資料欄,具有指定的空間類型和 SRID (空間參考系統識別碼):
$table->geography('coordinates', subtype: 'point', srid: 4326);
📌 備註
空間類型支援取決於您的資料庫驅動程式。請參閱您的資料庫文件。如果您的應用程式使用 PostgreSQL 資料庫,您必須在可以使用 geography
方法之前安裝 PostGIS 擴充功能。
geometry()
geometry
方法會建立一個 GEOMETRY
等效資料欄,具有指定的空間類型和 SRID (空間參考系統識別碼):
$table->geometry('positions', subtype: 'point', srid: 0);
📌 備註
空間類型支援取決於您的資料庫驅動程式。請參閱您的資料庫文件。如果您的應用程式使用 PostgreSQL 資料庫,您必須在可以使用 geometry
方法之前安裝 PostGIS 擴充功能。
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');
當使用 SQLite 時,將會建立一個 TEXT
資料欄。
jsonb()
jsonb
方法會建立一個 JSONB
等效資料欄:
$table->jsonb('options');
當使用 SQLite 時,將會建立一個 TEXT
資料欄。
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 BIGINT
、CHAR(36)
或 CHAR(26)
。
此方法旨在用於定義多型 Eloquent 關聯 所需的資料欄。在以下範例中,將會建立 taggable_id
和 taggable_type
資料欄:
$table->morphs('taggable');
nullableMorphs()
此方法類似於 morphs 方法;然而,所建立的資料欄將是「可為空 (nullable)」的:
$table->nullableMorphs('taggable');
nullableUlidMorphs()
此方法類似於 ulidMorphs 方法;然而,所建立的資料欄將是「可為空 (nullable)」的:
$table->nullableUlidMorphs('taggable');
nullableUuidMorphs()
此方法類似於 uuidMorphs 方法;然而,所建立的資料欄將是「可為空 (nullable)」的:
$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_at
和 updated_at
TIMESTAMP
(帶時區) 等效資料欄,並可選地帶有秒數小數精確度:
$table->timestampsTz(precision: 0);
timestamps()
timestamps
方法會建立 created_at
和 updated_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
等效資料欄。
此方法旨在用於定義多型 Eloquent 關聯 所需的資料欄,這些關聯使用 ULID 識別符。在以下範例中,將會建立 taggable_id
和 taggable_type
資料欄:
$table->ulidMorphs('taggable');
uuidMorphs()
uuidMorphs
方法是一個方便的方法,它會增加一個 {column}_id
CHAR(36)
等效資料欄和一個 {column}_type
VARCHAR
等效資料欄。
此方法旨在用於定義多型 Eloquent 關聯 所需的資料欄,這些關聯使用 UUID 識別符。在以下範例中,將會建立 taggable_id
和 taggable_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');
資料欄修飾符
除了上方列出的資料欄類型之外,還有數種資料欄「修飾符」可用於向資料庫資料表新增資料欄。例如,若要讓資料欄「可為 Null」,您可以使用 nullable
方法:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});
下表包含所有可用的資料欄修飾符。此列表不包含索引修飾符:
Modifier | Description |
---|---|
->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();
});
}
};
⚠️ 警告
預設表達式的支援程度取決於您的資料庫驅動程式、資料庫版本和欄位類型。請參閱您的資料庫文件。
資料欄順序
使用 MariaDB 或 MySQL 資料庫時,可以使用 after
方法在 Schema 中現有資料欄之後新增資料欄:
$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();
});
修改資料欄時,您必須明確包含要保留在資料欄定義上的所有修飾符——任何遺漏的屬性都將被捨棄。例如,若要保留 unsigned
、default
和 comment
屬性,您在修改資料欄時必須明確呼叫每個修飾符:
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();
重新命名資料欄
若要重新命名資料欄,您可以使用 Schema Builder 提供的 renameColumn
方法:
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});
刪除資料欄
若要刪除資料欄,您可以使用 Schema Builder 上的 dropColumn
方法:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});
您可以透過向 dropColumn
方法傳遞資料欄名稱陣列,從資料表刪除多個資料欄:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});
可用命令別名
Laravel 提供了數種與刪除常見資料欄類型相關的便捷方法。下表描述了這些方法:
Command | Description |
---|---|
$table->dropMorphs('morphable'); | 刪除 morphable_id 和 morphable_type 資料欄。 |
$table->dropRememberToken(); | 刪除 remember_token 資料欄。 |
$table->dropSoftDeletes(); | 刪除 deleted_at 資料欄。 |
$table->dropSoftDeletesTz(); | dropSoftDeletes() 方法的別名。 |
$table->dropTimestamps(); | 刪除 created_at 和 updated_at 資料欄。 |
$table->dropTimestampsTz(); | dropTimestamps() 方法的別名。 |
索引
建立索引
Laravel 的 schema builder 支援多種索引類型。以下範例會建立一個新的 email
資料欄,並指定其值應該是 unique 的。要建立索引,我們可以將 unique
方法鏈接到資料欄定義上:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});
另外,你也可以在定義資料欄之後再建立索引。為此,你應該在 schema builder blueprint 上呼叫 unique
方法。此方法接受應該接收 unique 索引的資料欄名稱:
$table->unique('email');
你甚至可以將一個資料欄陣列傳遞給索引方法,以建立複合式 (compound 或 composite) 索引:
$table->index(['account_id', 'created_at']);
建立索引時,Laravel 會根據資料表、資料欄名稱和索引類型自動產生索引名稱,但你也可以傳遞第二個參數給該方法,來自訂索引名稱:
$table->unique('email', 'unique_email');
可用的索引類型
Laravel 的 schema builder Blueprint class 提供了用於建立 Laravel 支援的每種索引類型的方法。每個索引方法都接受一個可選的第二個參數,以指定索引的名稱。如果省略,名稱將根據資料表、用於索引的資料欄名稱以及索引類型推導而來。每個可用的索引方法都將在下表中描述:
Command | Description |
---|---|
$table->primary('id'); | 新增 primary key。 |
$table->primary(['id', 'parent_id']); | 新增複合鍵。 |
$table->unique('email'); | 新增 unique 索引。 |
$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 會根據資料表名稱、索引資料欄名稱和索引類型自動分配索引名稱。以下是一些範例:
Command | Description |
---|---|
$table->dropPrimary('users_id_primary'); | 從 "users" 資料表刪除 primary key。 |
$table->dropUnique('users_email_unique'); | 從 "users" 資料表刪除 unique 索引。 |
$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...
});
⚠️ 警告
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 | 資料庫 Schema 傾印已完成。 |
Illuminate\Database\Events\SchemaLoaded | 現有的資料庫 Schema 傾印已載入。 |