Уяви, що ти пишеш книгу. Але ось халепа: не завжди все йде за планом. Іноді ти пишеш цілий розділ, але перечитуючи розумієш, що 5-й параграф вийшов жахливим. Що ти робиш? Ти ж не викидаєш весь розділ у смітник, правда? Замість цього ти редагуєш тільки ті місця, які викликають сумніви.
Приблизно так само працює і SAVEPOINT у PostgreSQL. Він дозволяє тобі:
- Створювати точки збереження всередині транзакції — як закладки в книзі.
- Повернутись до цих точок, щоб скасувати частину виконаних операцій, не відкочуючи всю транзакцію.
- Продовжувати роботу з рештою даних, не починаючи операцію заново.
Основний синтаксис SAVEPOINT
Команди, пов’язані з використанням SAVEPOINT, досить прості. Ось їх базовий набір:
Створення точки збереження (SAVEPOINT):
SAVEPOINT savepoint_name;
Це схоже на те, як ти кажеш: "Давайте запам’ятаємо це місце, раптом потім треба буде повернутись сюди."
Відкат до створеної точки збереження (ROLLBACK TO SAVEPOINT):
ROLLBACK TO SAVEPOINT savepoint_name;
Якщо щось пішло не так, ти повертаєшся до вказаного SAVEPOINT і скасовуєш всі зміни, зроблені з моменту його створення.
RELEASE SAVEPOINT):
RELEASE SAVEPOINT savepoint_name;
Це звільнить місце, де була "закладка". Після цього ти вже не зможеш відкотитись до цієї точки.
Простий приклад: покупка в інтернет-магазині
Давай уявимо, що ми керуємо інтернет-магазином. Клієнт додає в кошик кілька товарів, і ми хочемо виконати транзакцію, яка включає оформлення замовлення і зміни в таблиці складських залишків. Але якщо один з етапів не вийде, ми хочемо скасувати тільки частину транзакції, а не все.
BEGIN;
-- Крок 1: Забронювати товар "Книга SQL"
UPDATE inventory SET stock = stock - 1 WHERE product_id = 101;
-- Створюємо точку збереження
SAVEPOINT book_reserved;
-- Крок 2: Забронювати товар "Горнятко PostgreSQL"
UPDATE inventory SET stock = stock - 1 WHERE product_id = 102;
-- Ой-ой, виявилось, що на складі немає горняток!
ROLLBACK TO SAVEPOINT book_reserved;
-- Фіксуємо зміни тільки для книги
COMMIT;
Що відбувається в цьому прикладі?
- Ми почали транзакцію за допомогою
BEGIN. - Після бронювання книги створили точку збереження
book_reserved. Це наш перший "чекпоінт". - Спробували забронювати горнятко, але сталася помилка (наприклад, на складі не виявилось потрібного товару).
- Ми відкотились до точки збереження
book_reserved, щоб скасувати тільки зміни, пов’язані з горнятком. - Нарешті, ми зафіксували зміни по книзі за допомогою
COMMIT.
Більш складний приклад: багатоетапна обробка даних
Тепер уяви, що ти працюєш із системою керування замовленнями, де треба оновити кілька таблиць: orders (замовлення), inventory (складські залишки) і billing (виставлені рахунки). Якщо на якомусь етапі стається збій, ти не хочеш втрачати прогрес в інших таблицях. Ось тут SAVEPOINT рятує.
BEGIN;
-- Крок 1: Створити нове замовлення
INSERT INTO orders (order_id, customer_id, status) VALUES (1, 123, 'pending');
SAVEPOINT after_order_created;
-- Крок 2: Оновити залишки на складі
UPDATE inventory SET stock = stock - 2 WHERE product_id = 101;
SAVEPOINT after_stock_updated;
-- Крок 3: Провести оплату
INSERT INTO billing (order_id, amount, status) VALUES (1, 100, 'paid');
-- Ой, помилка: кредитна картка відхилена!
ROLLBACK TO SAVEPOINT after_stock_updated;
-- Ми повернулись на крок після оновлення залишку, але замовлення залишається в статусі "pending".
UPDATE orders SET status = 'failed' WHERE order_id = 1;
COMMIT;
Зверни увагу, як ми за допомогою SAVEPOINT розділили транзакцію на логічні етапи і повернулись до потрібної точки, зберігши частину змін.
Корисні поради при роботі з SAVEPOINT
- Використовуй осмислені імена точок збереження. У прикладах вище
after_order_createdнабагато інформативніше, ніж простоstep1. - Вкладені точки збереження працюють коректно: ти можеш створювати
SAVEPOINTнавіть всередині відкату до іншої точки. - Звільняй ресурси, видаляючи непотрібні точки через
RELEASE SAVEPOINT. Це може покращити продуктивність, особливо у великих транзакціях.
Реальні сценарії використання
Обробка банківських операцій: Наприклад, при переказі суми між кількома рахунками ти можеш відкотитись до певного етапу, якщо один з переказів завершився невдало.
Імпорт даних з файлів: Якщо ти імпортуєш великий CSV-файл, ти можеш перевіряти кожен рядок і виконувати відкат тільки для помилкових даних, зберігаючи успішні.
Масове оновлення записів: Якщо у тебе складний SQL-скрипт для оновлення тисяч рядків, SAVEPOINT дозволяє відкотитись до попереднього етапу, якщо виникла помилка посеред виконання.
Типові помилки і пастки
Іноді використання SAVEPOINT може призвести до неочікуваних результатів, якщо ти не розумієш, як вони працюють. Наприклад:
- Якщо ти забув відкотитись до точки збереження або видалити її, ти можеш створити ситуації, де ресурси блокуються до завершення транзакції.
SAVEPOINTне може скасувати дії, які відбулись до створення точки збереження. Наприклад, дані, зафіксовані черезCOMMIT, вже неможливо відкотити.
Тепер ти можеш безпечно експериментувати в транзакціях, створюючи точки збереження там, де це потрібно. Попереду ще більше SQL-практики, тож готуйся до наступної порції пригод.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ