Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що таке SAVEPOINT і як працюють «вкладені» транзакції?

Справжніх вкладених транзакцій у PostgreSQL немає. Натомість є точки збереження (savepoints) - мітки всередині транзакції, до яких можна відкотити частину змін, не скасовуючи все.

BEGIN;
INSERT INTO orders (id, total) VALUES (1, 500);

SAVEPOINT before_bonus;
INSERT INTO bonuses (order_id, amount) VALUES (1, 50);   -- помилка: порушено обмеження
ROLLBACK TO SAVEPOINT before_bonus;                       -- скасовано лише бонус

COMMIT;   -- замовлення збережено

Навіщо:

  • Обробити помилку й продовжити. У PostgreSQL будь-яка помилка переводить транзакцію в стан «aborted» - наступні команди відхиляються до ROLLBACK. Savepoint дозволяє відкотитися до точки й піти далі.
  • Масовий імпорт з пропуском поганих рядків - savepoint перед кожним рядком (або порцією).
  • Вкладені виклики коду, кожен з яких «хоче транзакцію».

Як це використовує Laravel: вкладений DB::transaction() усередині іншої транзакції створює savepoint, а не новий BEGIN:

DB::transaction(function () {
    Order::create([...]);

    try {
        DB::transaction(fn () => Bonus::create([...]));   // SAVEPOINT trans2
    } catch (QueryException $e) {
        // відкотилося лише створення бонусу
    }
});

Підводні камені:

  • COMMIT savepoint'а нічого не фіксує: зміни всередині стануть постійними лише з COMMIT зовнішньої транзакції. Якщо вона відкотиться, відкотиться все.
  • Ціна: кожен savepoint споживає ресурси. Тисячі savepoint'ів в одній транзакції (по одному на рядок) помітно сповільнюють роботу - для масового імпорту краще перевіряти дані до вставки чи використовувати ON CONFLICT.
  • Побічні ефекти поза базою (листи, HTTP-запити) відкат savepoint'а не скасує.

Докладніше в документації: SAVEPOINT

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання