# Транзакции ← [Назад к разделу БД](README.md) Транзакции гарантируют, что группа изменений применится «всё или ничего». --- ## Методы ```php DB::startTransaction(); // начать DB::commit(); // подтвердить DB::rollback(); // откатить ``` Поддерживаются вложенные транзакции (через `nested_transactions` — внутренние уровни эмулируются savepoint-логикой менеджера транзакций). ### Действие после commit Внешний HTTP, отправку писем, публикацию в соцсеть и другие необратимые действия не запускайте до подтверждения БД. Зарегистрируйте callback: ```php DB::startTransaction(); try { DB::Insert($orders, $order); DB::afterCommit(function () use ($order) { OrderNotifications::created($order); }); DB::commit(); } catch (\Throwable $e) { DB::rollback(); throw $e; } ``` Внутри транзакции callback выполняется после успешного внешнего `commit()`. При `rollback()` он удаляется. Если активной транзакции нет, `DB::afterCommit()` выполняет callback сразу. Исключение callback журналируется и не может отменить уже подтверждённую транзакцию, поэтому интеграция должна быть идемпотентной. --- ## Базовый паттерн Всегда оборачивайте тело в `try/catch` и откатывайте на ошибке: ```php DB::startTransaction(); try { DB::Insert($orders, $order); $orderId = (int) DB::insertId(); foreach ($items as $item) { $item['order_id'] = $orderId; DB::Insert($orderItems, $item); } DB::Update($stock, array('qty' => DB::sqlEval('qty - 1')), 'id = %i', $productId); DB::commit(); } catch (\Throwable $e) { DB::rollback(); throw $e; // или обработать/залогировать } ``` --- ## Когда нужны - Несколько связанных записей должны примениться вместе (заказ + позиции + остатки). - Пакетные операции, где частичный результат недопустим. - Перенос/пересчёт данных. ## Когда не нужны - Одиночный `INSERT`/`UPDATE`/`DELETE` — он и так атомарен. - Только чтение (`SELECT`). --- ## Подводные камни - **Не забывайте `commit()`** — без него по завершении запроса изменения откатятся. - Не смешивайте с DDL (`ALTER`, `CREATE`) — в MySQL они вызывают неявный commit. - Держите транзакцию **короткой**: не делайте внутри неё внешних HTTP-вызовов и долгих операций — это держит блокировки.