Пошук уроків, статей та іншого контенту
Дізнаєтеся, як зберігати UUID, генерувати їх і використовувати як ідентифікатори записів.
UUID (Universally Unique Identifier) — універсальний унікальний ідентифікатор. Це значення довжиною 128 біт, яке зазвичай записують у шістнадцятковому форматі:
550e8400-e29b-41d4-a716-446655440000UUID складається з 32 шістнадцяткових символів і чотирьох дефісів. Він має тип uuid у PostgreSQL.
UUID часто використовують як ідентифікатор запису замість послідовного числа:
1
2
3або:
550e8400-e29b-41d4-a716-446655440000На відміну від числового ідентифікатора, UUID складніше вгадати. Це корисно, коли ідентифікатор передається у вебадресі або API.
uuidЩоб створити стовпець для UUID, потрібно вказати тип uuid:
CREATE TABLE users (
id uuid PRIMARY KEY,
email text NOT NULL
);PostgreSQL перевіряє, чи є значення коректним UUID. Наприклад, такий запис є правильним:
INSERT INTO users (id, email)
VALUES (
'550e8400-e29b-41d4-a716-446655440000',
'anna@example.com'
);Регістр шістнадцяткових символів не має значення:
SELECT
'550E8400-E29B-41D4-A716-446655440000'::uuid;Оператор ::uuid явно перетворює текстове значення на тип uuid.
Найчастіше UUID не створюють вручну. Його генерує PostgreSQL під час вставлення запису.
Для цього можна використати функцію gen_random_uuid(). У деяких версіях PostgreSQL для її використання потрібно підключити розширення pgcrypto:
CREATE EXTENSION IF NOT EXISTS pgcrypto;Після цього функцію можна викликати напряму:
SELECT gen_random_uuid();Кожен виклик повертає новий UUID:
SELECT gen_random_uuid(), gen_random_uuid();Функцію генерації можна вказати як значення за замовчуванням для стовпця:
CREATE TABLE products (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
name text NOT NULL,
price numeric(10, 2) NOT NULL
);Тепер під час вставлення не потрібно вказувати id:
INSERT INTO products (name, price)
VALUES ('Клавіатура', 2499.00);PostgreSQL автоматично згенерує UUID.
Перевірити створений запис можна так:
SELECT id, name, price
FROM products;Якщо id не вказано, використовується вираз DEFAULT, тобто викликається gen_random_uuid().
Нижче наведено приклад, який можна виконати в PostgreSQL:
-- Підключаємо розширення для генерації випадкових UUID
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Видаляємо таблицю, якщо вона вже існує
DROP TABLE IF EXISTS orders;
-- Створюємо таблицю замовлень
CREATE TABLE orders (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
customer_email text NOT NULL,
status text NOT NULL DEFAULT 'new',
created_at timestamptz NOT NULL DEFAULT now()
);
-- UUID для цих записів буде створено автоматично
INSERT INTO orders (customer_email)
VALUES
('anna@example.com'),
('oleh@example.com');
-- Отримуємо всі замовлення
SELECT id, customer_email, status, created_at
FROM orders
ORDER BY created_at;
-- Знаходимо конкретне замовлення за UUID
SELECT id, customer_email, status
FROM orders
WHERE id = '550e8400-e29b-41d4-a716-446655440000'::uuid;У останньому запиті UUID наведено лише як приклад. У реальному застосунку потрібно використовувати UUID, який фактично належить запису.
UUID добре підходить для первинного ключа:
CREATE TABLE accounts (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
username text NOT NULL UNIQUE
);Обмеження PRIMARY KEY означає, що:
значення id не може бути NULL;
кожне значення id має бути унікальним;
PostgreSQL створює індекс для цього стовпця.
Вставлення нового облікового запису:
INSERT INTO accounts (username)
VALUES ('olena');Вставлення з отриманням створеного UUID:
INSERT INTO accounts (username)
VALUES ('taras')
RETURNING id, username;Ключове слово RETURNING повертає значення, створені або змінені під час операції.
Якщо UUID уже зберігається у змінній застосунку, його можна передати як параметр запиту:
SELECT id, username
FROM accounts
WHERE id = $1;Значення $1 має бути рядком із коректним UUID. Наприклад:
550e8400-e29b-41d4-a716-446655440000Параметризовані запити важливі, оскільки вони відокремлюють дані від SQL-коду. Не потрібно складати SQL-рядок конкатенацією значень, отриманих від користувача.
UUID можна використовувати і як зовнішній ключ:
CREATE TABLE customers (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
email text NOT NULL UNIQUE
);
CREATE TABLE customer_orders (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
customer_id uuid NOT NULL REFERENCES customers(id),
total numeric(10, 2) NOT NULL
);Спочатку створюємо клієнта й отримуємо його UUID:
INSERT INTO customers (email)
VALUES ('customer@example.com')
RETURNING id;Отриманий id можна використати для створення замовлення:
INSERT INTO customer_orders (customer_id, total)
VALUES (
'550e8400-e29b-41d4-a716-446655440000'::uuid,
1500.00
);Обмеження REFERENCES customers(id) не дозволить створити замовлення для клієнта, якого не існує.
serial або identityЧисловий ідентифікатор зазвичай виглядає так:
CREATE TABLE numeric_users (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
username text NOT NULL
);UUID має інші властивості:
його можна генерувати без спільного лічильника;
його складніше передбачити;
він зручний для розподілених систем, де записи створюються в різних сервісах;
він займає більше місця, ніж integer або bigint;
UUID менш зручний для читання людиною.
Вибір залежить від вимог проєкту. Якщо достатньо простого внутрішнього ідентифікатора, числовий ключ часто є зручнішим. Якщо важливі непередбачуваність або створення ідентифікаторів у різних системах, UUID може бути кращим вибором.
Таке визначення таблиці не генерує UUID автоматично:
CREATE TABLE users (
id uuid PRIMARY KEY,
email text NOT NULL
);Під час кожної вставки потрібно буде передавати id вручну. Для автоматичної генерації додайте:
id uuid PRIMARY KEY DEFAULT gen_random_uuid()Якщо PostgreSQL не знаходить gen_random_uuid(), підключіть pgcrypto:
CREATE EXTENSION IF NOT EXISTS pgcrypto;Для виконання цієї команди потрібні відповідні права в базі даних.
textМожна створити стовпець типу text, але це зазвичай гірше:
CREATE TABLE incorrect_users (
id text PRIMARY KEY
);У такому разі PostgreSQL не перевіряє формат UUID. У стовпець можна випадково записати довільний текст. Якщо значення є UUID, використовуйте тип uuid:
CREATE TABLE correct_users (
id uuid PRIMARY KEY DEFAULT gen_random_uuid()
);Цей запит завершиться помилкою:
SELECT 'not-a-uuid'::uuid;Застосунок має перевіряти вхідні дані або коректно обробляти помилку PostgreSQL.
UUID для пошуку має бути тим самим, що збережений у записі:
-- Це шукає UUID, створений під час виконання запиту,
-- а не конкретний запис із таблиці
SELECT *
FROM accounts
WHERE id = gen_random_uuid();Такий запит майже напевно не поверне рядків, адже кожен виклик генерує нове значення. Для пошуку потрібно передати конкретний UUID:
SELECT *
FROM accounts
WHERE id = '550e8400-e29b-41d4-a716-446655440000'::uuid;PostgreSQL має спеціальний тип uuid для UUID.
UUID можна використовувати як первинний або зовнішній ключ.
Функція gen_random_uuid() генерує випадковий UUID.
Для автоматичної генерації використовуйте DEFAULT gen_random_uuid().
Розширення pgcrypto можна підключити командою CREATE EXTENSION IF NOT EXISTS pgcrypto.
UUID потрібно зберігати як uuid, а не як звичайний текст.
Для пошуку передавайте вже відомий UUID, а не викликайте функцію генерації повторно.