Savepoint: контрольные точки внутри транзакции

Внутренние точки сохранения: зачем и когда? 🎯

Транзакции — это атомарные операции, но иногда нужно больше гибкости внутри них. Savepoint — это "чекпоинт" внутри транзакции, позволяющий откатиться не полностью, а до определённой точки.

👉 Где применяется:

  • Сложные миграции данных с промежуточными этапами
  • Многошаговые операции с возможностью частичного отката
  • Тестирование подзапросов без завершения транзакции
BEGIN;  -- Начало транзакции

INSERT INTO users (name) VALUES ('Alice');
SAVEPOINT first_user;  -- Создали точку сохранения!

INSERT INTO users (name) VALUES ('Bob');
-- Ой, что-то пошло не так...
ROLLBACK TO first_user;  -- Откатились до точки, Bob не добавился

COMMIT;  -- Фиксируем только Alice

Синтаксис Savepoint: просто как 1-2-3 🧩

Создание точки сохранения

SAVEPOINT имя_точки;  -- Без кавычек, регистр зависит от СУБД

Возврат к точке

ROLLBACK TO [SAVEPOINT] имя_точки;  -- Ключевое слово SAVEPOINT опционально

Удаление точки

RELEASE SAVEPOINT имя_точки;  -- Освобождает ресурсы

Важно: В PostgreSQL точки автоматически удаляются при COMMIT/ROLLBACK всей транзакции.


Реальный кейс: обработка заказов с резервированием 🛒

Представьте интернет-магазин, где нужно:

  1. Зарезервировать товар
  2. Создать заказ
  3. Списать деньги
  4. Обновить статистику

При ошибке на шаге 3 нужно отменить списание, но сохранить заказ в логе.

BEGIN;

-- 1. Резервируем товар
UPDATE products SET stock = stock - 1 WHERE id = 123;
SAVEPOINT stock_updated;

-- 2. Создаём заказ
INSERT INTO orders (product_id, user_id) VALUES (123, 456);
SAVEPOINT order_created;

-- 3. Пытаемся списать деньги (но вдруг ошибка?)
-- Предположим, тут произошла ошибка платежа
ROLLBACK TO order_created;  -- Отменяем только списание

-- 4. Фиксируем остальные изменения
COMMIT;

Глубокое погружение: как это работает под капотом 🔍

  1. Хранение: Savepoints записываются в специальную область памяти транзакции.
  2. Вложенность: Можно создавать точки внутри точек (как матрёшка).
  3. Производительность: Каждый SAVEPOINT — небольшой оверхед, но дешевле полного ROLLBACK.
BEGIN;
SAVEPOINT A;
    INSERT INTO table1 VALUES (1);
    SAVEPOINT B;
        INSERT INTO table1 VALUES (2);
        ROLLBACK TO B;  -- Удалится только значение 2
    INSERT INTO table1 VALUES (3);
COMMIT;  -- В таблице будут 1 и 3

Ограничения и особенности 🚧

  1. Не все СУБД поддерживают: MySQL, PostgreSQL, Oracle — да; SQLite — с ограничениями.
  2. Вложенность: В PostgreSQL до 64 уровней.
  3. Именование: Некоторые системы требуют уникальных имён в пределах транзакции.
-- Пример для MySQL
START TRANSACTION;
SAVEPOINT point_a;
SAVEPOINT point_a;  -- Ошибка: дублирование имени

Практическое задание 🛠️

Создайте транзакцию для перевода денег между счетами:

  1. Начало транзакции
  2. Проверка баланса (точка сохранения)
  3. Списание со счёта А
  4. Зачисление на счёт Б
  5. Если ошибка на шаге 4 — откат до проверки баланса
Скрыть рекламу навсегда

🧠 Учёба без воды и зубрёжки

Закрытый Boosty с наработками опытного преподавателя.

Объясняю сложное так, чтобы щелкнуло.

🚀 Забрать доступ к Boosty