Laravel и ULID

Laravel ULID

В прошлой статье мы разобрались как в Laravel работать с UUID. Но он не решает всех проблем распределенных систем. Один из новых подходов к генерации уникальных идентификаторов это ULID — Universally Unique Lexicographically Sortable Identifier (универсальный уникальный лексографически сортируемый идентификатор).

Сравнение UUID и ULID

Во многих случаях использование UUID неоптимально:

  • Это не самый эффективный способ кодирования 128-битной случайности
  • UUID v1/v2 непрактичен во многих средах, так как требует доступа к уникальному стабильному MAC-адресу
  • UUID v3/v5 требует уникального начального числа и генерирует случайно распределенные идентификаторы, которые могут вызвать фрагментацию во многих структурах данных
  • UUID v4 не предоставляет никакой другой информации, кроме случайности, которая может вызвать фрагментацию во многих структурах данных

Вместо этого ULID предлагает:

  • 128-битная совместимость с UUID
  • 1.21e+24 уникальных ключей в миллисекунду
  • Лексикографическая сортировка (т.е. в алфавитном порядке)
  • Канонически кодируется как 26-символьная строка, в отличие от 36-символьного UUID
  • Использует Crockford Base32 для лучшей эффективности и читаемости (5 бит на символ). Исключены буквы I, L, O, чтобы не путать с цифрами. И буква U, чтобы случайно не сгенерировались непристойность
  • Регистронезависимый
  • Без специальных символов (безопасный URL)
  • Точность метки времени до миллисекунды
  • Да просто выглядит эстетичнее, чем UUID :)

Более подробно можно узнать в спецификации ULID

Пример ULID:

ulid();
// 01d85pp1982gf6ktvfhq7w78fb

01d85pp198      2gf6ktvfhq7w78fb
Timestamp          Randomness
 48bits              80bits

 

Когда нужен ULID в качестве первичного ключа?

В распределенных системах, когда нужна уверенность, что у идентификаторов не будет коллизий. В высоконагруженной системы, когда автоинкрементный ключ не вариант.
Когда нужна репликация без геморроя (в отличии от int). Когда не хотите показывать пользователю, что получаете информацию об идентификаторе (например: example.com/user/3)

Использование ULID в Laravel

Ставим пакет

composer require rorecek/laravel-ulid:^2.0.0

Создаём модель

php artisan make:model Product -mcr

 

Исправляем в миграции модели строку
$table->increments('id');
на
$table->char('id', 26)->primary();

Если связанная модель использует ULID, то тип колонки должен это отображать

Schema::create('products', function (Blueprint $table) {
  $table->char('id', 26)->primary();
  ....
  // связанная модель
  $table->char('category_id', 26);
  $table->foreign('category_id')->references('id')->on('categories');
  ....
  $table->timestamps();
});

В модели укажите использование трейта HasUlid и выставьте флаг incrementing на false.

use Illuminate\Database\Eloquent\Model;
use Rorecek\Ulid\HasUlid;

class Product extends Model
{
  use HasUlid;
  ....

  /**
  * Indicates if the IDs are auto-incrementing.
  *
  * @var bool
  */
  public $incrementing = false;

  ....
}

Теперь, когда вы создаете новый экземпляр модели, ULID генерируется автоматически.

$item = Product::create();
echo $item->id;
// 01d85pp1982gf6ktvfhq7w78fb

 

Автор: Demiurge Ash