資料庫:遷移
簡介
遷移就像是資料庫的版本控制,讓您的團隊能夠定義和共享應用程式的資料庫架構定義。如果您曾經不得不告訴隊友從源代碼控制中拉取您的更改後,手動將一個欄位添加到他們的本地資料庫架構中,那麼您已經遇到了遷移解決的問題。
Laravel Schema Facades 提供了跨所有 Laravel 支持的資料庫系統創建和操作表的支持。通常,遷移將使用這個 Facade 來創建和修改資料庫表和欄位。
生成遷移
您可以使用 make:migration Artisan 指令 來生成一個資料庫遷移。新的遷移將放置在您的 database/migrations 目錄中。每個遷移文件名都包含一個時間戳,這使 Laravel 能夠確定遷移的順序:
php artisan make:migration create_flights_table
Laravel 將使用遷移的名稱來嘗試猜測表的名稱以及遷移是否將建立新表。如果 Laravel 能夠從遷移名稱中確定表名,Laravel 將使用指定的表預先填充生成的遷移文件。否則,您可以在遷移文件中手動指定表。
如果您想為生成的遷移指定自定義路徑,您可以在執行 make:migration 命令時使用 --path 選項。給定的路徑應該相對於您應用程序的基本路徑。
[!NOTE]
遷移樣板可以使用 樣板發布 進行自定義。
合併遷移
隨著應用程序的構建,您可能會隨著時間累積越來越多的遷移。這可能導致您的 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 目錄中寫入一個“schema”文件。模式文件的名稱將對應到數據庫連接。現在,當您嘗試遷移數據庫且沒有執行其他遷移時,Laravel 將首先執行數據庫連接的模式文件中的 SQL 語句。執行模式文件的 SQL 語句後,Laravel 將執行未包含在模式轉儲中的任何剩餘遷移。
如果您的應用程序測試使用與您在本地開發期間通常使用的不同數據庫連接,您應確保已使用該數據庫連接轉儲了模式文件,以便您的測試能夠構建您的數據庫。您可能希望在轉儲通常在本地開發期間使用的數據庫連接後執行此操作:
php artisan schema:dump
php artisan schema:dump --database=testing --prune
你應該將你的資料庫結構檔案提交到源代碼控制,這樣你團隊中的新開發人員可以快速建立應用程式的初始資料庫結構。
[!WARNING]
遷移壓縮僅適用於 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
{
// ...
}
執行遷移
要執行所有未完成的遷移,執行 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
[!WARNING]
為了使用此功能,您的應用程式必須使用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
[!WARNING]
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 的任何 column methods 來定義資料表的欄位。
確定表格/欄位存在性
您可以使用 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...
}
資料庫連線和表格選項
如果您想對非應用程式預設連線的資料庫連線執行結構操作,請使用 connection 方法:
Schema::connection('sqlite')->create('users', function (Blueprint $table) {
$table->id();
});
此外,還可以使用一些其他屬性和方法來定義表格建立的其他方面。當使用 MariaDB 或 MySQL 時,可以使用 engine 屬性來指定表格的儲存引擎:
Schema::create('users', function (Blueprint $table) {
$table->engine('InnoDB');
// ...
});
charset 和 collation 屬性可用於指定在使用 MariaDB 或 MySQL 時為建立的表格指定字元集和校對:
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 門面上的 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 門面上的 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');
});
可用的欄位類型
結構生成器藍圖提供了各種方法,對應於您可以添加到資料庫表中的不同類型的欄位。下表列出了每個可用方法:
布林類型
字串和文字類型
char longText mediumText string text tinyText
數值類型
bigIncrements bigInteger decimal double float id increments integer mediumIncrements mediumInteger smallIncrements smallInteger tinyIncrements tinyInteger unsignedBigInteger unsignedInteger unsignedMediumInteger unsignedSmallInteger unsignedTinyInteger
日期和時間類型
dateTime dateTimeTz date time timeTz timestamp timestamps timestampsTz softDeletes softDeletesTz year
二進制類型
物件和 JSON 類型
UUID 和 ULID 類型
ulid ulidMorphs uuid uuidMorphs nullableUlidMorphs nullableUuidMorphs
空間類型
關係類型
專用類型
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 等效列:
$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 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 方法使用給定的空間類型和 SRID(空間參考系統標識符)創建一個等效的 GEOGRAPHY 欄位:
$table->geography('coordinates', subtype: 'point', srid: 4326);
> [!NOTE]
> 空間類型的支援取決於您的資料庫驅動程式。請參考您資料庫的文件。如果您的應用程式使用 PostgreSQL 資料庫,您必須在使用 geography 方法之前安裝 PostGIS 擴充功能。
geometry()
geometry 方法使用給定的空間類型和 SRID(空間參考系統標識符)創建一個等效的 GEOMETRY 欄位:
$table->geometry('positions', subtype: 'point', srid: 0);
> [!NOTE]
> 空間類型的支援取決於您的資料庫驅動程式。請參考您資料庫的文件。如果您的應用程式使用 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 時,您可以將二進制字符集應用於欄位,以創建一個 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 方法;但是,創建的欄位將是“可為空”:
$table->nullableMorphs('taggable');
nullableUlidMorphs()
此方法類似於 ulidMorphs 方法;但是,創建的欄位將是“可為空”:
$table->nullableUlidMorphs('taggable');
nullableUuidMorphs()
此方法類似於 uuidMorphs 方法;但是,創建的欄位將是“可為空”:
$table->nullableUuidMorphs('taggable');
rememberToken()
rememberToken 方法創建一個可為空的 VARCHAR(100) 等效的欄位,用於存儲當前的“記住我” 身份驗證標記:
```php
$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 等效的欄位。
此方法旨在在定義需要使用 ULID 識別符的多態 Eloquent 關係 所需的欄位時使用。在下面的示例中,將創建 taggable_id 和 taggable_type 欄位:
$table->ulidMorphs('taggable');
uuidMorphs()
uuidMorphs 方法是一個方便的方法,它會新增一個 {column}_id CHAR(36) 等效的欄位和一個 {column}_type VARCHAR 等效的欄位。
這個方法旨在在定義需要使用 UUID 識別符的多態 Eloquent 關聯 所需的欄位時使用。在下面的示例中,將創建 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');
欄位修飾符
除了上面列出的欄位類型外,在將欄位添加到資料庫表時,您可以使用幾個欄位“修飾符”。例如,要使欄位“可為空”,您可以使用 nullable 方法:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});
以下表格包含所有可用的欄位修飾符。此列表不包括 索引修飾符: