Блог Горошко Андрея 1C-Битрикс Транзакции в Битрикс: Как обеспечить целостность данных с startTransaction, commit и rollback

Транзакции в Битрикс: Как обеспечить целостность данных с startTransaction, commit и rollback

Представьте ситуацию: вам нужно списать деньги с одного счета и зачислить их на другой.

Это две отдельные SQL-операции (UPDATE).

Что, если первая выполнится успешно, а вторая — с ошибкой? Деньги «повиснут в воздухе».

Чтобы предотвратить такие проблемы, существуют транзакции.

Транзакция — это механизм базы данных, который гарантирует, что группа из нескольких SQL-операций будет выполнена по принципу «всё или ничего».

Либо все операции в группе успешно завершаются, либо все они полностью отменяются.

Когда нужно использовать транзакции?

  • Когда операция состоит из двух и более взаимосвязанных запросов на изменение данных (INSERT, UPDATE, DELETE).
  • При проведении заказов (списание со склада, создание оплаты).
  • При сложных операциях импорта данных.
  • При любых действиях, где частичное выполнение недопустимо.

Как работать с транзакциями в Битрикс D7

Современный способ — использовать методы объекта соединения D7.

Основной шаблон:

use Bitrix\Main\Application;
use Bitrix\Main\DB\Connection;

/** @var Connection $connection */
$connection = Application::getConnection();

try {
    // 1. Начинаем транзакцию
    $connection->startTransaction();

    // --- Выполняем группу операций ---
    // Например, обновление элемента ORM
    $result1 = \My\Table::update(1, ['QUANTITY' => 5]);
    if (!$result1->isSuccess()) {
        // Если первая операция не удалась, выбрасываем исключение
        throw new \Exception(implode(', ', $result1->getErrorMessages()));
    }
    
    // И еще одна операция
    $result2 = \My\AnotherTable::add(['ITEM_ID' => 1, 'STATUS' => 'PROCESSED']);
    if (!$result2->isSuccess()) {
        // Если вторая операция не удалась, выбрасываем исключение
        throw new \Exception(implode(', ', $result2->getErrorMessages()));
    }
    // ---------------------------------

    // 2. Если все прошло успешно, "коммитим" транзакцию
    $connection->commitTransaction();
    
    echo "Все операции успешно выполнены!";

} catch (\Exception $e) {
    // 3. Если на любом этапе возникло исключение, "откатываем" транзакцию
    $connection->rollbackTransaction();
    
    echo "Произошла ошибка, все изменения отменены: " . $e->getMessage();
}

Разбор шагов:

  1. $connection->startTransaction(): Подает базе данных команду начать новую транзакцию. Все последующие SQL-запросы будут выполняться «виртуально» в рамках этой транзакции.
  2. Блок try: Здесь размещается вся ваша бизнес-логика. Важно проверять результат каждой операции и в случае неудачи немедленно прерывать выполнение, выбрасывая исключение.
  3. $connection->commitTransaction(): Если код дошел до этой строки, значит, все операции в блоке try прошли без ошибок. Эта команда говорит базе данных: «Все в порядке, сохрани все изменения, сделанные с начала транзакции».
  4. Блок catch и $connection->rollbackTransaction(): Если в блоке try было выброшено исключение, выполнение переходит в catch. Команда rollbackTransaction говорит базе данных: «Отмени все изменения, сделанные с начала этой транзакции».

Старый API ($DB)

Аналогичные методы есть и у глобального объекта $DB:

  • $DB->StartTransaction()
  • $DB->Commit()
  • $DB->Rollback()

Логика их использования точно такая же.

Вложенные транзакции

D7 ORM поддерживает вложенные транзакции. Если вы вызовете startTransaction() внутри уже начатой транзакции, Битрикс создаст «точку сохранения» (SQL SAVEPOINT). commitTransaction() во вложенной транзакции ничего не сделает, а rollbackTransaction() откатит изменения только до этой точки сохранения. Это сложный механизм, и в 99% случаев лучше избегать вложенных транзакций, выстраивая логику линейно.

ДействиеПоведение
startTransaction() внутри другойСоздаёт точку сохранения
commitTransaction() вложеннойНе сохраняет в БД, ждёт внешнего коммита
rollbackTransaction() вложеннойОткат до SAVEPOINT, выбрасывает TransactionException

Рекомендация: избегайте вложенных откатов. Управление ошибками должно быть в основной транзакции.

Обработка ошибок во вложенных транзакциях

use Bitrix\Main\DB\TransactionException;

function updateAccounts(int $userId, Connection $db) {
    try {
        $db->startTransaction();
        // Логика обновления
        $db->commitTransaction();
    } catch (Throwable $e) {
        $db->rollbackTransaction();
        throw $e;
    }
}

function updateOrders(int $userId, Connection $db) {
    try {
        $db->startTransaction();
        // Логика обновления
        $db->commitTransaction();
    } catch (Throwable $e) {
        $db->rollbackTransaction();
        throw $e;
    }
}

$db = Application::getConnection();

try {
    $db->startTransaction();

    updateOrders($userId, $db);    // Вложенная
    updateAccounts($userId, $db);  // Вложенная

    $db->commitTransaction();
} catch (TransactionException $e) {
    $db->rollbackTransaction(); // Откат всей транзакции
} catch (Throwable $e) {
    $db->rollbackTransaction();
    throw $e;
}

Практические советы

  • Делайте транзакции короткими — это снижает риск блокировок
  • Проверяйте результат каждой операции (isSuccess())
  • Логируйте ошибки и исключения
  • Не смешивайте ORM и SQL без крайней необходимости
  • Если используете DataManager::getConnectionName, убедитесь, что транзакция охватывает нужное соединение

Архитектурные нюансы

  • Вложенные транзакции — мощный инструмент, но требуют строгой дисциплины
  • Ошибки во вложенной транзакции могут не остановить внешнюю — это опасно
  • Лучше использовать линейную логику и централизованную обработку ошибок

Вывод:
Транзакции — это обязательный инструмент для написания надежного кода, который изменяет данные.

Всегда оборачивайте группы взаимосвязанных add, update или delete операций в блок try…catch с startTransaction и commit/rollback.

Это единственный способ гарантировать целостность и консистентность вашей базы данных.


транзакции Битрикс, startTransaction, commitTransaction, rollbackTransaction, целостность данных, D7, Application::getConnection, SQL.

Похожая задача в бизнесе?

Помогу автоматизировать процессы и внедрить ИИ

Меня зовут Андрей Горошко. Я Full-stack разработчик и эксперт по 1С-Битрикс. Настраиваю CRM Битрикс24, разрабатываю защищенные API и создаю умных ИИ-агентов для автоматизации рутины.

Добавить комментарий

Related Post

Создание дилерского кабинета для производителей спецодежды и средств защитыСоздание дилерского кабинета для производителей спецодежды и средств защиты

Разработка и внедрение профессионального B2B-портала и дилерского кабинета на 1С-Битрикс позволяет кардинально сократить издержки отдела оптовых продаж, перевести дилеров на самообслуживание 24/7 и исключить ошибки ручного ввода заказов. Услуга «Создание

Изменить свойство товаров или вариаций catalog.productProperty.updateИзменить свойство товаров или вариаций catalog.productProperty.update

Оптимизация производительности и безопасности — залог успешного проекта на 1С-Битрикс. Данный материал посвящен практическому применению «Изменить свойство товаров или вариаций catalog.productProperty.update». Мы подготовили подробный разбор принципов работы и развернутые примеры

Results And Errors: Руководство разработчикаResults And Errors: Руководство разработчика

Каждый PHP-разработчик, работающий с экосистемой Bitrix Framework, должен глубоко понимать работу её ключевых компонентов. В этой статье мы проведем подробный аудит темы «Results And Errors: Руководство разработчика», проанализируем лучшие практики