Laravel でテーブルの ID を ULID に指定する方法
こんにちは。 SAW です。
最近急に寒くなってきましたね。季節の変わり目で体調を崩さないように、体調管理には気をつけてくださいね。
Laravel の migration でテーブルを作成する際に、 Illuminate\Database\Schema\Blueprint::id()
を利用することで、 連番の ID を生成します。
しかし、 ID を連番にすると、レコードが削除された場合に ID が歯抜けになり得ます。
また、1 つ目の参考文献 に挙げられているデメリットもあります。
連番の ID を用いるかわりに、 ULID を利用することで、ソート可能なランダムな文字列 を ID として扱えます。
本記事では、 Laravel でテーブルの ID を ULID に指定する方法を紹介します。
なお、本記事では Laravel のバージョンが 10.x 系 を前提としています。
対象読者
本記事で想定する読者層は次の通りです。
- Laravel の基本的な知識を有している
- データベースについての基本的な知識を有している
ULID とは
本章では、 UUID について説明したあと、 UUID と ULID を比較しながら、 ULID はどのようなものかを説明します。
UUID とは
UUID (Universally Unique IDentifier) とは、世界中で一意かつランダムな ID です。
同じ UUID が生成される確率は非常に小さい ため、生成される UUID は世界中で一意になることが保証されています。
UUID には複数のバージョンがあります。
- UUIDv1: 時刻と MAC アドレスに基づいて UUID を生成
- UUIDv2: DCOM (Distributed Component Object Model) のために予約されている
- 一般的に利用されていないのが実情
- UUIDv3: 名前と名前空間を MD5 でハッシュ化した値に基づいて UUID を生成
- 同じ名前空間上で同じ名前であれば同じ UUID が生成可能
- UUIDv4: 乱数に基づいて UUID を生成
- 最も広く利用されている UUID のバージョン
- UUIDv5: UUIDv3 のハッシュ関数を SHA-1 にしたもの
UUID と ULID の違い
ULID (Universally Unique Lexicographically Sortable Identifier) も UUID と同様に、世界中で一意かつランダムな ID です。
ULID が UUID と異なる主な点は次の通りです。
-
生成された順にソート可能 である
- 一般的に利用されている UUIDv4 はソートすると生成順にならない
- 英数字の 36 文字でエンコーディングされた文字列で表現される
- UUID は 32 桁の 16 進数で表現される
UUID/ULID を ID にすることで、 ID がランダムな文字列になり、連番のような ID の歯抜けを気にする必要がなく、 ID が推測されづらくなります。
また、 ULID を利用することで、 ID 順でレコードの生成順にソートできます。
Laravel で primary key を ULID にする方法
本章では、 Laravel で migration を行う際に、テーブルの primary key を ULID に指定する方法を紹介します。
migration file で ULID を指定する方法
Laravel では、テーブルのカラムの型に ULID を指定するためのメソッドとして、 Illuminate\Database\Schema\Blueprint::ulid()
が用意されています。
ulid()
を利用した場合、デフォルトのカラム名は ulid
になります。
ulid()
の引数に文字列を指定することで、引数の文字列がカラム名になります。
id()
と異なり、 ulid()
では自動的に PRIMARY KEY 制約が設定されません。
別テーブルから外部キーで参照する場合、 primary()
で PRIMARY KEY 制約を付与 します。
テーブルの primary key を ULID に指定するコード例は以下の通りです。
Schema::create('users', function (Blueprint $table) {
$table->ulid('id')->primary(); # カラム id を ULID の primary key に指定
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
});
ULID の値をテーブルに流し込む方法
ULID の値をテーブルに流し込むには、 Illuminate\Support\Str::ulid()
を利用します。
Laravel で用意されている UserFactory
を用いて User
のインスタンスを生成する際に ULID の値を流し込む方法は次の通りです。
public function definition(): array
{
return [
'id' => Str::ulid(), # id に ULID の値を登録
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
'remember_token' => Str::random(10),
];
}
Str::ulid()
が実行されるたびに、異なる ULID が都度生成されます。
そのため、上記の factory から生成された User
のインスタンスをテーブルに流し込むと、 ID はそれぞれ異なる ULID が格納されます。
まとめ
本記事のまとめは次の通りです。
- ULID とは世界中で一意でランダムかつソート可能な ID である
- migration file で
ulid()
を利用することで ULID のカラムを作成できる -
Str::ulid()
で ULID の値を生成できる- seeder や factory 経由でテーブルに ULID の値を格納できる
あらためて Laravel には様々な機能が準備されていて便利だと実感しました。
参考文献
Discussion