翻譯進度
52.99% 已翻譯
更新時間:
2024年6月30日 上午8:27:00 [世界標準時間]
翻譯人員:
幫我們翻譯此頁

資料庫:Migration

簡介

Migration(移轉)」就像是資料表的版本控制一樣,我們能通過 Migration 來定義並與開發團隊共享專案的資料庫結構定義。讀者是否曾經在從版控拉去更新後,還需要告訴同事要手動新增欄位?資料庫 Migration 就是要解決這樣的問題。

Laravel 的 Schema Facade 提供了一種可建立或修改資料表的功能,該功能不區分資料,可用在所有 Laravel 支援的資料庫系統上。一般來說,Migration 會使用該 Facade 來建立或修改資料庫資料表與欄位。

產生 Migration

我們可以使用 make:migration Artisan 指令 來產生資料庫 Migration。新建立的 Migration 會放在 database/migrations 目錄下。各個 Migration 的檔名都包含了一個時戳,用來讓 Laravel 判斷各個 Migration 的執行順序:

1php artisan make:migration create_flights_table
1php artisan make:migration create_flights_table

Laravel 會使用 Migration 的名稱來嘗試推測資料表的名稱,並嘗試推測該 Migration 是否要建立新資料表。若 Laravel 可判斷檔案名稱,則 Laravel 會預先在產生的 Migration 檔中填入特定的資料表。若無法判斷時,我們只需要在 Migration 檔中手動指定資料表即可。

若想為產生的 Migration 檔指定自訂的路徑,則可在執行 make:migration 指令時使用 --path 選項。給定的路徑應為相對於專案根目錄的相對路徑。

lightbulb

可以安裝 Stub 來自訂 Migration 的 Stub。

壓縮 Migration

在我們持續撰寫專案的同時,我們可能會逐漸累積出越來越多的資料庫 Migration 檔。這樣可能會導致 database/migrations 目錄中包含了數百個 Migration 檔。若有需要的話,我們可以將 Migration 檔「壓縮」進單一 SQL 檔內。要開始壓縮,請執行 schema:dump 指令:

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

執行該指令時,Laravel 會將一個「Schema(結構描述)」檔案寫入 database/schema 目錄內。Schema 檔案的名稱對影到資料庫連線的名稱。當要移轉資料庫時,若尚未執行過任何 Migration,Laravel 會先執行目前正在使用的資料庫連線所對應 Schema 檔中的 SQL。執行完 Schema 檔內的陳述式後,Laravel 才會接著執行不在該 Schema 傾印中剩下的 Migration。

若專案的測試使用的資料庫連線與本機開發環境所使用的連線不同時,請確認是否有使用該資料庫連線傾印 Schema 檔案,這樣測試中才能正常的建立資料庫。通常這個步驟應放在將開發環境所使用的資料庫連線傾印出來之後:

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

請將資料庫 Schema 檔 Commit(簽入) 進版本控制中,好讓團隊中其他的新開發人員可快速建立專案的初始資料庫結構。

lightbulb

Migration squashing is only available for the MySQL, PostgreSQL, and SQLite databases and utilizes the database's command-line client.

Migration 的架構

Migration 類別中包含了兩個方法:updownup 方法可用來在資料庫中新增新資料表、欄位、索引等;而 down 方法則用來做與 up 方法相反的事。

在這兩個方法中,我們可以使用 Laravel 的 Schema Builder 來以描述性的方法建立與修改資料表。若要瞭解 Schema Builder 中所有可用的方法,請參考 Schema Builder 的說明文件。舉例來說,下列 Migration 會建立一個 flights 資料表:

1<?php
2 
3use Illuminate\Database\Migrations\Migration;
4use Illuminate\Database\Schema\Blueprint;
5use Illuminate\Support\Facades\Schema;
6 
7return new class extends Migration
8{
9 /**
10 * Run the migrations.
11 */
12 public function up(): void
13 {
14 Schema::create('flights', function (Blueprint $table) {
15 $table->id();
16 $table->string('name');
17 $table->string('airline');
18 $table->timestamps();
19 });
20 }
21 
22 /**
23 * Reverse the migrations.
24 */
25 public function down(): void
26 {
27 Schema::drop('flights');
28 }
29};
1<?php
2 
3use Illuminate\Database\Migrations\Migration;
4use Illuminate\Database\Schema\Blueprint;
5use Illuminate\Support\Facades\Schema;
6 
7return new class extends Migration
8{
9 /**
10 * Run the migrations.
11 */
12 public function up(): void
13 {
14 Schema::create('flights', function (Blueprint $table) {
15 $table->id();
16 $table->string('name');
17 $table->string('airline');
18 $table->timestamps();
19 });
20 }
21 
22 /**
23 * Reverse the migrations.
24 */
25 public function down(): void
26 {
27 Schema::drop('flights');
28 }
29};

Setting the Migration Connection

若 Migration 會使用與專案預設資料庫連線不同的資料庫連線,則請在 Migration 中設定 $connection 屬性:

1/**
2 * The database connection that should be used by the migration.
3 *
4 * @var string
5 */
6protected $connection = 'pgsql';
7 
8/**
9 * Run the migrations.
10 */
11public function up(): void
12{
13 // ...
14}
1/**
2 * The database connection that should be used by the migration.
3 *
4 * @var string
5 */
6protected $connection = 'pgsql';
7 
8/**
9 * Run the migrations.
10 */
11public function up(): void
12{
13 // ...
14}

執行 Migration

若要執行所有尚未執行過的 Migration,請執行 migrate Artisan 指令:

1php artisan migrate
1php artisan migrate

若想檢視目前為止已執行了哪些 Migration,可使用 migrate:status Artisan 指令:

1php artisan migrate:status
1php artisan migrate:status

若想檢視 Migration 中會執行的 SQL 陳述式而不實際執行這些 SQL,則可提供 --pretend 旗標給 migrate 指令:

1php artisan migrate --pretend
1php artisan migrate --pretend

獨立執行 Migration

若專案會被部署到多個伺服器上,而 Migration 是部署流程的一部分的話,我們通常不會希望有兩台 Server 同時嘗試執行資料庫移轉。若要避免有兩台 Server 同時執行,可以在呼叫 migrate 指令時加上 isolated 選項。

提供了 isolated 選項後,Laravel 會嘗試使用專案的快取 Driver 來取得一個 Atomic Lock(不可部分完成鎖定),然後再執行 Migration。當 Lock 被鎖住時,嘗試執行 migrate 指令就不會執行。不過,這些不被執行的 migrate 指令仍然會回傳成功的終止狀態代碼:

1php artisan migrate --isolated
1php artisan migrate --isolated
lightbulb

若要使用此功能,則應用程式必須要使用 memcached, redis, dynamodb, database, filearray 作為應用程式的預設快取 Driver。另外,所有的伺服器也都必須要連線至相同的中央快取伺服器。

Forcing Migrations to Run in Production

有些 Migration 中的動作是破壞性的,也就是一些會導致資料消失的動作。為了避免在正式環境資料庫中執行這些破壞性的動作,因此在執行指令時,會出現提示要求確認。若要強制該指令不跳出提示直接執行,請使用 --force 旗標:

1php artisan migrate --force
1php artisan migrate --force

復原 Migration

若要復原最後執行的 Migration 動作,可使用 rollback Artisan 指令。該指令會復原最後「一批」執行的 Migration,其中可能包含多個 Migration 檔:

1php artisan migrate:rollback
1php artisan migrate:rollback

我們也可以提供各一個 step 選項給 rollback 指令,以限制要復原的 Migration 數量。舉例來說,下列指令只會復原最後 5 個 Migration:

1php artisan migrate:rollback --step=5
1php artisan migrate:rollback --step=5

只要提供 batch 選項給 rollback 指令,就可以復原特定「批次」的 Migration。這裡的 batch 選項,對應到專案資料庫中 migrations 資料表的 batch 值。舉例來說,下列指令會復原所有第 3 批次的 Migration:

1php artisan migrate:rollback --batch=3
1php artisan migrate:rollback --batch=3

若想檢視 Migration 中會執行的 SQL 陳述式而不實際執行這些 SQL,則可提供 --pretend 旗標給 migrate:rollback 指令:

1php artisan migrate:rollback --pretend
1php artisan migrate:rollback --pretend

migrate:reset 指令會復原專案中所有的 Migration:

1php artisan migrate:reset
1php artisan migrate:reset

Roll Back and Migrate Using a Single Command

migrate:refresh 指令會將所有的 Migration 都復原回去,並接著執行 migrate 指令。使用該指令,就可以有效率的重建整個資料庫:

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

我們也可以提供各一個 step 選項給 refresh 指令,以限制要復原並重新 Migrate 的 Migration 數量。舉例來說,下列指令只會復原並重新 Migrate 最後 5 個 Migration:

1php artisan migrate:refresh --step=5
1php artisan migrate:refresh --step=5

Drop All Tables and Migrate

migrate:fresh 指令會刪除資料庫中所有資料表,並接著執行 migrate 指令:

1php artisan migrate:fresh
2 
3php artisan migrate:fresh --seed
1php artisan migrate:fresh
2 
3php artisan migrate:fresh --seed

By default, the migrate:fresh command only drops tables from the default database connection. However, you may use the --database option to specify the database connection that should be migrated. The database connection name should correspond to a connection defined in your application's database configuration file:

1php artisan migrate:fresh --database=admin
1php artisan migrate:fresh --database=admin
lightbulb

不論資料表是否有前置詞 (Prefix),migrate:fresh 指令會刪除所有的資料庫資料表。在使用與其他專案共享的資料庫時,若要與本指令搭配使用請務必注意。

資料表

建立資料表

若要建立新的資料庫資料表,請使用 Schema Facade 上的 create 方法。create 方法接受兩個引數:資料表名稱、以及一個接收 Blueprint 物件的閉包。Blueprint 物件可用來定義新資料表:

1use Illuminate\Database\Schema\Blueprint;
2use Illuminate\Support\Facades\Schema;
3 
4Schema::create('users', function (Blueprint $table) {
5 $table->id();
6 $table->string('name');
7 $table->string('email');
8 $table->timestamps();
9});
1use Illuminate\Database\Schema\Blueprint;
2use Illuminate\Support\Facades\Schema;
3 
4Schema::create('users', function (Blueprint $table) {
5 $table->id();
6 $table->string('name');
7 $table->string('email');
8 $table->timestamps();
9});

建立資料表時,我們可以使用任意 Schema Builder 的欄位方法來定義資料表欄位。

Determining Table / Column Existence

You may determine the existence of a table, column, or index using the hasTable, hasColumn, and hasIndex methods:

1if (Schema::hasTable('users')) {
2 // The "users" table exists...
3}
4 
5if (Schema::hasColumn('users', 'email')) {
6 // The "users" table exists and has an "email" column...
7}
8 
9if (Schema::hasIndex('users', ['email'], 'unique')) {
10 // The "users" table exists and has a unique index on the "email" column...
11}
1if (Schema::hasTable('users')) {
2 // The "users" table exists...
3}
4 
5if (Schema::hasColumn('users', 'email')) {
6 // The "users" table exists and has an "email" column...
7}
8 
9if (Schema::hasIndex('users', ['email'], 'unique')) {
10 // The "users" table exists and has a unique index on the "email" column...
11}

Database Connection and Table Options

若要在非專案預設連線的資料庫連線上做 Schema 動作,請使用 connection 方法:

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

此外,還有一些其他的屬性或方法,可用來調整資料表建立中的其他細節。使用 MySQL 時,可使用 engine 屬性來指定資料表的 Storage Engine:

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

使用 MySQL 時,charsetcollation 屬性可用來指定建立資料表的 Character Set 與 Collection:

1Schema::create('users', function (Blueprint $table) {
2 $table->charset('utf8mb4');
3 $table->collation('utf8mb4_unicode_ci');
4 
5 // ...
6});
1Schema::create('users', function (Blueprint $table) {
2 $table->charset('utf8mb4');
3 $table->collation('utf8mb4_unicode_ci');
4 
5 // ...
6});

temporary 方法可用來表示該資料表是「臨時」資料表。臨時資料表只可在目前連線的資料庫工作階段中使用,且會在連線關閉後自動刪除:

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

If you would like to add a "comment" to a database table, you may invoke the comment method on the table instance. Table comments are currently only supported by MySQL and PostgreSQL:

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

更新資料表

Schema Facade 上的 table 方法可用來更新現有的資料表。與 create 方法類似,table 方法接受兩個因數:資料表名稱,以及一個接收 Blueprint 實體的閉包。使用 Blueprint 實體,即可用來在資料表上新增欄位或索引:

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

重新命名或刪除資料表

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

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

若要移除現有的資料表,可使用 dropdropIfExists 方法:

1Schema::drop('users');
2 
3Schema::dropIfExists('users');
1Schema::drop('users');
2 
3Schema::dropIfExists('users');

與外部索引鍵一起重新命名資料表

在重新命名資料表時,請務必確認該資料表上的外部索引鍵條件(Foreign Key Constraint)是否有直接設定名稱,而不是使用 Laravel 所指定的基於慣例的名稱。若未直接設定名稱,則這些外部索引鍵條件的名稱可能會參照到舊的資料表名稱:

欄位

建立欄位

Schema Facade 上的 table 方法可用來更新現有的資料表。與 create 方法類似,table 方法接受兩個因數:資料表名稱,以及一個接收 Illuminate\Database\Schema\Blueprint 實體的閉包。使用這個 Blueprint 實體,即可用來在資料表上新增欄位或索引:

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

可用的欄位型別

Schema Builder Blueprint 提供了多種方法,這些方法對應到可新增至資料庫資料表中各種不同的欄位型別。可用的各個方法列在下表中:

bigIncrements()

bigIncrements 方法建立一個 Auto-Increment(自動遞增)UNSIGNED BIGINT (主索引鍵(Primary Key)) 或相等欄位:

1$table->bigIncrements('id');
1$table->bigIncrements('id');

bigInteger()

bigInteger 方法建立一個 BIGINT 或相等的欄位:

1$table->bigInteger('votes');
1$table->bigInteger('votes');

binary()

binary 方法建立一個 BLOB 或相等欄位:

1$table->binary('photo');
1$table->binary('photo');

When utilizing MySQL, MariaDB, or SQL Server, you may pass length and fixed arguments to create VARBINARY or BINARY equivalent column:

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

boolean()

boolean 方法建立一個 BOOLEAN 或相等欄位:

1$table->boolean('confirmed');
1$table->boolean('confirmed');

char()

char 方法以給定的長度來建立一個 CHAR 或相等欄位:

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

dateTimeTz()

The dateTimeTz method creates a DATETIME (with timezone) equivalent column with an optional fractional seconds precision:

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

dateTime()

The dateTime method creates a DATETIME equivalent column with an optional fractional seconds precision:

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

date()

date 方法會建立一個 DATE 或相等欄位:

1$table->date('created_at');
1$table->date('created_at');

decimal()

decimal 方法會以給定的精度(Precision) (總位數) 與小數位數(Scale) (小數位數) 來建立一個 DECIMAL 或相等欄位:

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

double()

The double method creates a DOUBLE equivalent column:

1$table->double('amount');
1$table->double('amount');

enum()

enum 方法以給定的有效值來建立一個 ENUM 或相等欄位:

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

float()

The float method creates a FLOAT equivalent column with the given precision:

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

foreignId()

foreignId 方法會建立一個 UNSIGNED BIGINT 或相等的欄位:

1$table->foreignId('user_id');
1$table->foreignId('user_id');

foreignIdFor()

foreignIdFor 方法會新增一個用於給定 Model 類別的 {column}_id 同等欄位。依照該 Model 的索引鍵型別,該欄位可能為 UNSIGNED BIGINTCHAR(36)CHAR(26)

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

foreignUlid()

foreignUlid 方法會建立一個 ULID 或相等欄位:

1$table->foreignUlid('user_id');
1$table->foreignUlid('user_id');

foreignUuid()

foreignUuid 方法會建立一個 UUID 或相等欄位:

1$table->foreignUuid('user_id');
1$table->foreignUuid('user_id');

geography()

The geography method creates a GEOGRAPHY equivalent column with the given spatial type and SRID (Spatial Reference System Identifier):

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

Support for spatial types depends on your database driver. Please refer to your database's documentation. If your application is utilizing a PostgreSQL database, you must install the PostGIS extension before the geography method may be used.

geometry()

The geometry method creates a GEOMETRY equivalent column with the given spatial type and SRID (Spatial Reference System Identifier):

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

Support for spatial types depends on your database driver. Please refer to your database's documentation. If your application is utilizing a PostgreSQL database, you must install the PostGIS extension before the geometry method may be used.

id()

id 欄位為 bigIncrements 方法的別名。預設情況下,該方法會建立一個 id 欄位。不過,若想為該欄位指定不同的名稱,也可以傳入欄位名稱:

1$table->id();
1$table->id();

increments()

increments 方法會建立一個 Auto-Increment(自動遞增)UNSIGNED INTEGER 或同等欄位作為主索引鍵(Primary Key)

1$table->increments('id');
1$table->increments('id');

integer()

integer 方法建立一個 INTEGER 或相等的欄位:

1$table->integer('votes');
1$table->integer('votes');

ipAddress()

ipAddress 方法會建立一個 VARCHAR 或相等欄位:

1$table->ipAddress('visitor');
1$table->ipAddress('visitor');

When using PostgreSQL, an INET column will be created.

json()

json 方法會建立一個 JSON 或相等欄位:

1$table->json('options');
1$table->json('options');

jsonb()

jsonb 方法會建立一個 JSONB 或相等欄位:

1$table->jsonb('options');
1$table->jsonb('options');

longText()

longText 方法建立一個 LONGTEXT 或相等欄位:

1$table->longText('description');
1$table->longText('description');

When utilizing MySQL or MariaDB, you may apply a binary character set to the column in order to create a LONGBLOB equivalent column:

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

macAddress()

macAddress 方法會建立一個用來保存 MAC 位址的欄位。在某些資料庫系統,如 PostgreSQL 中,有專門的欄位可用來保存這種類型的資料。在其他資料庫系統,則會使用相等的字串欄位:

1$table->macAddress('device');
1$table->macAddress('device');

mediumIncrements()

mediumIncrements 方法會建立一個 Auto-Increment(自動遞增)UNSIGNED MEDIUMINT 或同等欄位作為主索引鍵(Primary Key)

1$table->mediumIncrements('id');
1$table->mediumIncrements('id');

mediumInteger()

mediumInteger 方法建立一個 MEDIUMINT 或相等的欄位:

1$table->mediumInteger('votes');
1$table->mediumInteger('votes');

mediumText()

mediumText 方法建立一個 MEDIUMTEXT 或相等的欄位:

1$table->mediumText('description');
1$table->mediumText('description');

When utilizing MySQL or MariaDB, you may apply a binary character set to the column in order to create a MEDIUMBLOB equivalent column:

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

morphs()

morphs 方法會新增一個用於給定 Model 類別的 {column}_id 同等欄位與 {column}_type VARCHAR 同等欄位。依照該 Model 的索引鍵型別,{column}_id 欄位可能為 UNSIGNED BIGINTCHAR(36)CHAR(26) 型別。

該方法主要是要給多型 Eloquent 關聯定義欄位用的。在下列範例中,會建立 taggable_idtaggable_type 欄位:

1$table->morphs('taggable');
1$table->morphs('taggable');

nullableTimestamps()

nullabaleTimestamps 方法是 timestamps 方法的別名:

1$table->nullableTimestamps(precision: 0);
1$table->nullableTimestamps(precision: 0);

nullableMorphs()

該方法與 morphs 方法類似。不過,使用 nullableMorphs 方法建立的欄位會是「nullable」的:

1$table->nullableMorphs('taggable');
1$table->nullableMorphs('taggable');

nullableUlidMorphs()

該方法與 ulidMorphs 方法類似。不過,使用 ulidMorphs 方法建立的欄位會是「nullable」的:

1$table->nullableUlidMorphs('taggable');
1$table->nullableUlidMorphs('taggable');

nullableUuidMorphs()

該方法與 uuidMorphs 方法類似。不過,使用 nullableMorphs 方法建立的欄位會是「nullable」的:

1$table->nullableUuidMorphs('taggable');
1$table->nullableUuidMorphs('taggable');

rememberToken()

rememberToken 方法會建立一個 Nullable 的 VARCHAR(100) 或相等的欄位,用於存放目前的「記住我」身份驗證權杖

1$table->rememberToken();
1$table->rememberToken();

set()

set 方法會以給定的有效值來建立一個 SET 或相等欄位:

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

smallIncrements()

smallIncrements 方法會建立一個 Auto-Increment(自動遞增)UNSIGNED SMALLINT 或同等欄位作為主索引鍵(Primary Key)

1$table->smallIncrements('id');
1$table->smallIncrements('id');

smallInteger()

smallInteger 方法建立一個 SMALLINT 或相等的欄位:

1$table->smallInteger('votes');
1$table->smallInteger('votes');

softDeletesTz()

The softDeletesTz method adds a nullable deleted_at TIMESTAMP (with timezone) equivalent column with an optional fractional seconds precision. This column is intended to store the deleted_at timestamp needed for Eloquent's "soft delete" functionality:

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

softDeletes()

The softDeletes method adds a nullable deleted_at TIMESTAMP equivalent column with an optional fractional seconds precision. This column is intended to store the deleted_at timestamp needed for Eloquent's "soft delete" functionality:

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

string()

string 方法以給定的長度來建立一個 VARCHAR 或相等欄位:

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

text()

text 方法會建立一個 TEXT 或相等欄位:

1$table->text('description');
1$table->text('description');

When utilizing MySQL or MariaDB, you may apply a binary character set to the column in order to create a BLOB equivalent column:

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

timeTz()

The timeTz method creates a TIME (with timezone) equivalent column with an optional fractional seconds precision:

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

time()

The time method creates a TIME equivalent column with an optional fractional seconds precision:

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

timestampTz()

The timestampTz method creates a TIMESTAMP (with timezone) equivalent column with an optional fractional seconds precision:

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

timestamp()

The timestamp method creates a TIMESTAMP equivalent column with an optional fractional seconds precision:

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

timestampsTz()

The timestampsTz method creates created_at and updated_at TIMESTAMP (with timezone) equivalent columns with an optional fractional seconds precision:

1$table->timestampsTz(precision: 0);
1$table->timestampsTz(precision: 0);

timestamps()

The timestamps method creates created_at and updated_at TIMESTAMP equivalent columns with an optional fractional seconds precision:

1$table->timestamps(precision: 0);
1$table->timestamps(precision: 0);

tinyIncrements()

tinyIncrements 方法會建立一個 Auto-Increment(自動遞增)UNSIGNED TINYINT 或同等欄位作為主索引鍵(Primary Key)

1$table->tinyIncrements('id');
1$table->tinyIncrements('id');

tinyInteger()

tinyInteger 方法建立一個 TINYINT 或相等的欄位:

1$table->tinyInteger('votes');
1$table->tinyInteger('votes');

tinyText()

tinyText 方法建立一個 TINYTEXT 或相等欄位:

1$table->tinyText('notes');
1$table->tinyText('notes');

When utilizing MySQL or MariaDB, you may apply a binary character set to the column in order to create a TINYBLOB equivalent column:

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

unsignedBigInteger()

unsignedBigInteger 方法會建立一個 UNSIGNED BIGINT 或相等的欄位:

1$table->unsignedBigInteger('votes');
1$table->unsignedBigInteger('votes');

unsignedInteger()

unsignedInteger 方法會建立一個 UNSIGNED INTEGER 或相等的欄位:

1$table->unsignedInteger('votes');
1$table->unsignedInteger('votes');

unsignedMediumInteger()

unsignedMediumInteger 方法會建立一個 UNSIGNED MEDIUMINT 或相等的欄位:

1$table->unsignedMediumInteger('votes');
1$table->unsignedMediumInteger('votes');

unsignedSmallInteger()

unsignedSmallInteger 方法會建立一個 UNSIGNED SMALLINT 或相等的欄位:

1$table->unsignedSmallInteger('votes');
1$table->unsignedSmallInteger('votes');

unsignedTinyInteger()

unsignedTinyInteger 方法會建立一個 UNSIGNED TINYINT 或相等的欄位:

1$table->unsignedTinyInteger('votes');
1$table->unsignedTinyInteger('votes');

ulidMorphs()

ulidMorphs 是一個方便方法,會新增一個 {欄位}_id CHAR(26) 或相等欄位,以及一個 {欄位}_type VARCHAR 或相等欄位。

該方法主要是要給使用 ULID 作為識別字元的多型 Eloquent 關聯定義欄位用的。在下列範例中,會建立 taggable_idtaggable_type 欄位:

1$table->ulidMorphs('taggable');
1$table->ulidMorphs('taggable');

uuidMorphs()

uuidMorphs 是一個方便方法,會新增一個 {欄位}_id CHAR(36) 或相等欄位,以及一個 {欄位}_type VARCHAR 或想等欄位。

該方法主要是要給使用 UUID 作為識別字元的多型 Eloquent 關聯定義欄位用的。在下列範例中,會建立 taggable_idtaggable_type 欄位:

1$table->uuidMorphs('taggable');
1$table->uuidMorphs('taggable');

ulid()

ulid 方法會建立一個 ULID 或相等欄位:

1$table->ulid('id');
1$table->ulid('id');

uuid()

uuid 方法會建立一個 UUID 或相等欄位:

1$table->uuid('id');
1$table->uuid('id');

year()

year 方法會建立一個 YEAR 或相等欄位:

1$table->year('birth_year');
1$table->year('birth_year');

欄位修飾詞

除了上列欄位型別外,還有多種可在將欄位新增至資料表時使用的欄位「修飾詞」。舉例來說,若要將欄位設為「Nullable」,可使用 nullable 方法:

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

下表中包含了所有可用的修飾詞。該列表中未包含索引修飾詞

修飾詞 說明
->after('column') 將欄位放在另一個欄位「之後(After)」(MySQL)。
->autoIncrement() 將 INTEGER 欄位設為 Auto-Increment(自動遞增) (主索引鍵(Primary Key))。
->charset('utf8mb4') 指定用於該欄位的 Character Set (MySQL)。
->collation('utf8mb4_unicode_ci') Specify a collation for the column.
->comment('my comment') Add a comment to a column (MySQL / PostgreSQL).
->default($value) 為欄位指定「預設(Default)」值。
->first() 將欄位放在資料表中的「第一個(First)」欄位 (MySQL)。
->from($integer) 設定 Auto-Increment(自動遞增) 欄位的起始值 (MySQL / PostgreSQL)。
->invisible() 讓該欄位在 SELECT * 查詢中「不可見(Invisible)」(MySQL)。
->nullable($value = true) 允許將 NULL 值插入該欄位中。
->storedAs($expression) Create a stored generated column (MySQL / PostgreSQL / SQLite).
->unsigned() 將 INTEGER 欄位設為 UNSIGNED (MySQL)。
->useCurrent() 設定 TIMESTAMP 欄位使用 CURRENT_TIMESTAMP 作為預設值。
->useCurrentOnUpdate() 在資料更新時,將 TIMESTAMP 欄位設為 CURRENT_TIMESTAMP (MySQL)。
->virtualAs($expression) Create a virtual generated column (MySQL / SQLite).
->generatedAs($expression) 以指定的 Sequence(順序) 選項來建立 Identity 欄位 (PostgreSQL)。
->always() 定義一個優先使用 Sequence 值而不使用輸入值的 Identity 欄位 (PostgreSQL)。

預設運算式

default 修飾詞可接受 Illuminate\Database\Query\Expression 實體。使用 Expression 實體時,Laravel 就不會將輸入值包裝在引號內,能讓我們使用資料庫所提供的函式。有一些狀況特別適合使用這個方法,如要給 JSON 欄位指定預設值時:

1<?php
2 
3use Illuminate\Support\Facades\Schema;
4use Illuminate\Database\Schema\Blueprint;
5use Illuminate\Database\Query\Expression;
6use Illuminate\Database\Migrations\Migration;
7 
8return new class extends Migration
9{
10 /**
11 * Run the migrations.
12 */
13 public function up(): void
14 {
15 Schema::create('flights', function (Blueprint $table) {
16 $table->id();
17 $table->json('movies')->default(new Expression('(JSON_ARRAY())'));
18 $table->timestamps();
19 });
20 }
21};
1<?php
2 
3use Illuminate\Support\Facades\Schema;
4use Illuminate\Database\Schema\Blueprint;
5use Illuminate\Database\Query\Expression;
6use Illuminate\Database\Migrations\Migration;
7 
8return new class extends Migration
9{
10 /**
11 * Run the migrations.
12 */
13 public function up(): void
14 {
15 Schema::create('flights', function (Blueprint $table) {
16 $table->id();
17 $table->json('movies')->default(new Expression('(JSON_ARRAY())'));
18 $table->timestamps();
19 });
20 }
21};
lightbulb

對於預設運算式的支援程度會因資料庫 Driver、資料庫版本、欄位型別等而有所不同。請參考資料庫的說明文件。

欄位順序

在使用 MySQL 資料庫時,可使用 after 方法來將欄位插入到資料表結構中的某個現有欄位之後:

1$table->after('password', function (Blueprint $table) {
2 $table->string('address_line1');
3 $table->string('address_line2');
4 $table->string('city');
5});
1$table->after('password', function (Blueprint $table) {
2 $table->string('address_line1');
3 $table->string('address_line2');
4 $table->string('city');
5});

修改欄位

使用 change 欄位,即可修改現有欄位的型別或屬性。舉例來說,我們可以用來增加 string 欄位的大小。來看看使用 change 方法的例子,我們來把 name 欄位的大小從 25 增加到 50。若要增加 name 欄位的大小,我們只需要定義該欄位的新狀態,然後呼叫 change 方法即可:

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

When modifying a column, you must explicitly include all the modifiers you want to keep on the column definition - any missing attribute will be dropped. For example, to retain the unsigned, default, and comment attributes, you must call each modifier explicitly when changing the column:

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

The change method does not change the indexes of the column. Therefore, you may use index modifiers to explicitly add or drop an index when modifying the column:

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

重新命名欄位

若要重新命名欄位,可使用 Schema Builder 所提供的 renameColumn 方法:

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

刪除欄位

若要移除欄位,可使用 Schema Builder 所提供的 dropColumn 方法:

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

可以傳入一組欄位名稱的陣列給 dropColumn 方法來一次移除多個欄位:

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

可用的指令別名

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 的 Schema Builder 支援多種類型的索引。下列為一個建立新 email 欄位並指定該欄位值不可重複(Unique)的範例。若要建立索引,我們可以將 unique 方法串聯到欄位定義之後呼叫:

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

或者,我們也可以在定義完欄位後再建立索引。若要在定義欄位完後才建立索引,我們需要在 Schema Builder Blueprint 上呼叫 unique 方法。該方法的引數為要設為 Unique 索引的欄位名稱:

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

我們也可以傳入一組欄位的陣列給索引方法,以建立一個複合式(Compound) / 組合式(Composite)的索引

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

建立索引時,Laravel 會自動依據資料表名稱、欄位名稱、索引類型等來產生索引名稱。不過,我們也可以傳入第二個因數給該方法來自行指定索引名稱:

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

可用的索引類型

Laravel 的 Schema Builder Blueprint 為 Laravel 所支援的各種索引類型都提供了方法。每個索引方法都接受可選的第二引數,可用來指定索引的名稱。若未提供索引名稱,則會自動使用索引的資料表名稱、欄位名稱、以及索引型別等來產生索引名稱。下表為可用的索引方法:

指令 說明
$table->primary('id'); 新增主索引鍵(Primary Key)
$table->primary(['id', 'parent_id']); 新增複合式索引鍵(Composite Keys)
$table->unique('email'); 新增 Unique(不重複) 索引
$table->index('state'); 新增索引。
$table->fullText('body'); Adds a full text index (MySQL / PostgreSQL).
$table->fullText('body')->language('english'); 以指定的語言來新增全文索引 (PostgreSQL)。
$table->spatialIndex('location'); 新增 Spatial(空間) 索引 (除了 SQLite)。

重新命名索引

若要重新命名索引,可使用 Schema Builder Blueprint 提供的 renameIndex 方法。該方法的第一個引數為目前的索引名稱,而第二個引數則為要修改的名稱:

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

刪除索引

若要刪除索引,則需要指定索引的名稱。預設情況下,Laravel 會自動依照資料表名稱、索引欄位名稱、以及索引類型來指派索引名稱。範例如下:

指令 說明
$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'); 從「users」資料表中刪除全文索引。
$table->dropSpatialIndex('geo_location_spatialindex'); Drop a spatial index from the "geo" table (except SQLite).

在刪除索引上時,若傳入一組欄位陣列給該方法,則會自動依照資料表名稱、欄位名稱、索引型別等產生慣例式的索引名稱:

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

Foreign Key Constraint

在 Laravel 中,也可以建立 Foreign Key Constraint(外部索引鍵的條件約束)。使用 Foreigh Key Constraint,就可在資料庫層級上強制確保參照的完整性。舉例來說,我們來在 posts 資料表上定義一個參照到 users 資料表 id 欄位的 user_id 欄位:

1use Illuminate\Database\Schema\Blueprint;
2use Illuminate\Support\Facades\Schema;
3 
4Schema::table('posts', function (Blueprint $table) {
5 $table->unsignedBigInteger('user_id');
6 
7 $table->foreign('user_id')->references('id')->on('users');
8});
1use Illuminate\Database\Schema\Blueprint;
2use Illuminate\Support\Facades\Schema;
3 
4Schema::table('posts', function (Blueprint $table) {
5 $table->unsignedBigInteger('user_id');
6 
7 $table->foreign('user_id')->references('id')->on('users');
8});

由於這個語法有點複雜,因此 Laravel 提供了一個額外的、簡潔的方法。這種方法使用慣例,來提供更好的開發者經驗(DX)。在使用 foreignID 方法建立欄位時,上方的範例可以被這樣改寫:

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

foreignId 方法會建立一個 UNSIGNED BIGINT 或相等欄位,而 constrained 方法會使用慣例來判斷要參照的資料表與欄位。若表名不符合 Laravel 的慣例,則可以手動將資料庫表名稱提供給 constrained 方法。此外,也可以指定產生的索引名稱:

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

也可以指定 Constraint「on delete」與「on update」屬性的動作:

1$table->foreignId('user_id')
2 ->constrained()
3 ->onUpdate('cascade')
4 ->onDelete('cascade');
1$table->foreignId('user_id')
2 ->constrained()
3 ->onUpdate('cascade')
4 ->onDelete('cascade');

或者,也有比較描述性的語法可以設定這些動作:

方法 說明
$table->cascadeOnUpdate(); 更新時應串聯更新 (Cascade)。
$table->restrictOnUpdate(); 更新時應限制更新 (Restricted)。
$table->noActionOnUpdate(); No action on updates.
$table->cascadeOnDelete(); 刪除時應串聯刪除 (Cascade)。
$table->restrictOnDelete(); 刪除時應限制刪除 (Restricted)。
$table->nullOnDelete(); 刪除時應將外部索引鍵設為 null。

若有額外的欄位修飾詞,應將其放在 constrained 方法前呼叫:

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

刪除外部索引鍵

若要刪除 Foreign Key(外部索引鍵),可使用 dropForeign 方法,傳入要刪除的 Foreign Key Constraint(外部索引鍵條件約束) 名稱即可。Foreign Key Constraint 使用與索引相同的命名規範。換句話說,Foreign Key Constraint 的名稱會使用要約束的資料表名稱與欄位名稱組成,並在後方加上「_foreign」後置詞:

1$table->dropForeign('posts_user_id_foreign');
1$table->dropForeign('posts_user_id_foreign');

或者,也可以傳入一組包含欄位名稱的陣列給 dropForeign 方法。這組陣列中應包含 Foreign Key 的名稱。傳入該陣列後,Laravel 會使用約束的命名管理來將該陣列轉換為 Foreign Key Constraint 的名稱:

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

啟用/禁用 Foreign Key Constraint

可以使用下列方法來在 Migration 中啟用或禁用 Foreign Key Constraint:

1Schema::enableForeignKeyConstraints();
2 
3Schema::disableForeignKeyConstraints();
4 
5Schema::withoutForeignKeyConstraints(function () {
6 // Constraints disabled within this closure...
7});
1Schema::enableForeignKeyConstraints();
2 
3Schema::disableForeignKeyConstraints();
4 
5Schema::withoutForeignKeyConstraints(function () {
6 // Constraints disabled within this closure...
7});
lightbulb

SQLite 預設會禁用 Foreign Key Constraint。使用 SQLite 時,在 Migration 中建立 Foreign Key Constraint 前,請先檢查是否有在資料庫設定中啟用 Foreign Key 支援。此外,SQLite 只支援在建立資料表時設定 Foreign Key,而無法在修改資料表時新增

Event

為了讓開發更方便,Migration 中的各個動作都會分派 [Event(/docs/master/events)](事件)。下列的所有 Event 都繼承了 Illuminate\Database\Events\MigrationEvent 類別:

類別 說明
Illuminate\Database\Events\MigrationsStarted 即將執行一批 Migration。
Illuminate\Database\Events\MigrationsEnded 已完成執行一批 Migration。
Illuminate\Database\Events\MigrationStarted 即將執行單一 Migration。
Illuminate\Database\Events\MigrationEnded 已完成執行單一 Migration。
Illuminate\Database\Events\SchemaDumped 已傾印完成資料庫結構。
Illuminate\Database\Events\SchemaLoaded 已載入現有的資料庫結構傾印。
翻譯進度
52.99% 已翻譯
更新時間:
2024年6月30日 上午8:27:00 [世界標準時間]
翻譯人員:
幫我們翻譯此頁

留言

尚無留言

“Laravel” is a Trademark of Taylor Otwell.
The source documentation is released under MIT license. See laravel/docs on GitHub for details.
The translated documentations are released under MIT license. See cornch/laravel-docs-l10n on GitHub for details.