Вложенные транзакции Bitrix: Что это и как работает

Привет, Электрон на связи. Сегодня мы поговорим о том, как использовать транзакции в Bitrix, чтобы обеспечить целостность данных, какие изменения привнесла в мир 1С-Битрикса версия main 22.200.0 а также, что такое вложенные транзакции и для чего они нужны.

Кратко о тразакциях:

Транзакции играют ключевую роль в обеспечении целостности данных и обеспечивают корректное выполнение множественных операций с базой данных. Они объединяют несколько запросов в одну конструкцию, обеспечивая их либо полное выполнение, либо отмену в случае возникновения проблем.

Для чего нужны транзакции?

Внедрение вложенных транзакций расширяет возможности управления операциями. Создание точек сохранения при повторной инициации транзакции обеспечивает дополнительный уровень контроля. Необходимо осторожно подходить к использованию вложенных откатов, оставляя решение об этом на последний случай.

Как это было раньше:

Ранее, до введения транзакций в Bitrix, разработчики сталкивались с необходимостью разрабатывать сложные механизмы контроля изменений и восстановления данных в случае ошибок. Внедрение транзакций в Bitrix существенно упростило и обезопасило процесс управления данными, обеспечивая более надежные методы поддержания их целостности.

Какую роль выполняют методы управления транзакциями?

  • $connection->startTransaction();: Этот метод начинает транзакцию, позволяя группировать несколько операций в единое целое.
  • $connection->commitTransaction();: Вызов этого метода фиксирует все изменения, сделанные в рамках транзакции, и отправляет их в базу данных.
  • $connection->rollbackTransaction();: Если произошла ошибка или необходимо отменить все изменения в рамках транзакции, этот метод откатывает все операции.

<?php
$application = \Bitrix\Main\Application::getInstance();
$connection = $application->getConnection();
try {
$connection->startTransaction();
// Ваш код
$connection->commitTransaction();
}catch (\Throwable $e) {
$connection->rollbackTransaction();
throw $e;
}

Рассмотрим пример использования не вложенных транзакций. Допустим, у нас есть сущность, назовем ее Table. Мы хотим изменить поле NAME у записи с кодом 'example'. При этом, мы также хотим добавить новую запись в другую таблицу - AnotherTable.

В этом кусочке кода транзакция начинается, операции выполняются, и если что-то идет не так, мы можем легко и безопасно откатить все изменения.

<?php
$application = \Bitrix\Main\Application::getInstance();
$connection = $application->getConnection(); // Устанавливаем соединение с БД
try {
// Начинаем транзакцию
$connection->startTransaction();
// Получаем обьект сущности
$object = \Example\Table::query()
->where('CODE', 'example')
->addSelect('NAME')
->fetchObject();
if ($object) {
$object->set('NAME', 'Пример записи'); // Меняем поле `NAME` у объекта
$result = $object->save();
if (!$result->isSuccess()) {
thrownew \Bitrix\Main\SystemException('Ошибка в процессе сохранения данных.');
}
// Пробуем добавить еще один элемент в другую таблицу
$anotherObject = \Example\AnotherTable::createObject();
$anotherObject->set('TITLE', 'New title');
$result = $anotherObject->save();
if (!$result->isSuccess()) {
// В случае ошибки откатываем транзакцию, первый элемент не сохранится
thrownew \Bitrix\Main\SystemException('Ошибка в процессе сохранения данных.');
}
// Завершение транзакции
$connection->commitTransaction();
}else {
thrownew \Bitrix\Main\SystemException('Объект не найден.');
}
}catch (\Throwable $e) {
// Если произошла ошибка, отменяем транзакцию
$connection->rollbackTransaction();
throw $e;
}

Работа с вложенными транзакциями интереснее. Давайте рассмотрим более сложный пример, позволяющий разобраться и понять их функционал. В случае возникновения ошибки во вложенной транзакции, существует возможность либо отмены изменений в рамках данной транзакции с сохранением обновлений на более высоком уровне, либо полного отката с целью поддержания целостности данных.

<?php
$application = \Bitrix\Main\Application::getInstance();
$connection = $application->getConnection();
try {
// Начинаем транзакцию
$connection->startTransaction();
// Получаем объект
$object = \Example\Table::query()
->where('CODE', 'example')
->addSelect('NAME')
->fetchObject();
if ($object) {
$object->set('NAME', 'Пример записи'); // Меняем поле `NAME` у объекта
$result = $object->save(); // Сохраняем
if (!$result->isSuccess()) {
thrownew \Bitrix\Main\SystemException('Ошибка в процессе сохранения данных.');
}
// Пробуем добавить элемент в другую таблицу
$anotherObject = \Example\AnotherTable::createObject();
$anotherObject->set('TITLE', 'New title');
$result = $anotherObject->save(); // Сохраняем
if (!$result->isSuccess()) {
// В случае ошибки откатываем транзакцию, первый элемент не сохраняется
thrownew \Bitrix\Main\SystemException('Ошибка в процессе сохранения данных.');
}
// Вложенная транзакция
$connection->startTransaction();
// Создаем объект для вложенной таблицы
$nestedObject = \Example\NestedTable::createObject();
$nestedObject->set('DESCRIPTION', 'Nested description');
$result = $nestedObject->save();
if (!$result->isSuccess()) {
// В случае ошибки откатываем вложенную транзакцию
// Т.к у битрикса действует парадигма "вложенные роллбеки не поддерживаются"
// Происходит исключение \Bitrix\Main\DB\TransactionException
$connection->rollbackTransaction();
}else {
// Успешно завершаем вложенную транзакцию
$connection->commitTransaction();
}
// Успешно завершаем основную транзакцию
$connection->commitTransaction();
}else {
thrownew \Bitrix\Main\SystemException('Объект не найден.');
}
}catch (\Bitrix\Main\DB\TransactionException $e) {
// ROLLBACK вложенной транзакции
// Тут мы можем решить, что делать, если вложенная транзакция не прошла
}catch (\Throwable $e) {
// Если произошла ошибка, отменяем транзакцию
$connection->rollbackTransaction();
throw $e;
}

Дополнительно:

  • Транзакции применимы не только к save(), но и к другим методам ORM, таким как update(), add(). А также, к SQL запросам через $connection->query()
  • Если хотите углубиться в тайны транзакций, загляните в официальную документацию Bitrix

Итоги

Итак, в статье о вложенных транзакциях в Битриксе было рассмотрено важное понятие о возможности использования нескольких транзакций вложенно друг в друга. Это позволяет создавать более сложные иерархии операций с данными и обеспечивать целостность информации даже при выполнении различных действий. По сути, вложенные транзакции позволяют добиться более гибкого контроля изменений и возможности откатиться к предыдущему состоянию данных в случае необходимости. Такой подход особенно полезен в случаях, когда требуется выполнить серию связанных операций, где каждая операция зависит от успешного завершения предыдущей.

На связи была команда Электрон, спасибо за внимание и до встречи!

Начать дискуссию