? Привет! Сегодня мы поговорим о том, как использовать транзакции в Bitrix, чтобы обеспечить целостность данных. А также, что такое вложенные транзакции и для чего они нужны.
? Тайны Транзакций
Версия main 22.200.0 принесла с собой нечто волшебное - вложенные транзакции в Bitrix! Зачем они нужны? Давайте посмотрим на этот процесс с точки зрения магии.

Транзакции - это ваше надежное магическое заклинание, которое гарантирует, что ваши множественные изменения в базе данных будут выполнены целиком или полностью отменены, если что-то пошло не так.
С появлением вложенных транзакций, мы добавляем новый элемент магии. Теперь, при повторном старте транзакции, создаются точки сохранения. Вложенные транзакции поддерживаются, но решение о вложенных откатах лучше оставить конечному сценарию.
? Для чего нужны транзакции?
Транзакции позволяют объединять несколько запросов в единую конструкцию. Она гарантирует, что запросы будут выполнены как единое целое.
Транзакции - это нечто большее, чем просто блок кода. Это своего рода защитный механизм, который помогает вам избежать проблем с целостностью данных. Они гарантируют, что ваши операции с базой данных будут либо успешными, либо полностью отменены, если что-то пошло не так.
? Как это было раньше?
Прежде чем волшебство транзакций появилось в Bitrix, разработчики вынуждены были прибегать к тайным приемам.
Создание таблицы-шпиона, где каждое изменение регистрировалось. Это позволяло восстановить предыдущее состояние при ошибке.
Введение транзакций в Bitrix значительно улучшило этот процесс, предоставив более надежные и эффективные способы гарантировать целостность данных.
? Волшебство в действии: Как это работает в коде?
<?php
$application = \Bitrix\Main\Application::getInstance();
$connection = $application->getConnection();
try {
$connection->startTransaction();
// Ваш волшебный код здесь...
$connection->commitTransaction();
} catch (\Throwable $e) {
$connection->rollbackTransaction();
throw $e;
}
Окей, давайте рассмотрим пример использования транзакций на практике. Допустим, у нас есть сущность, назовем ее ExampleTable
. Мы хотим изменить поле NAME
у записи с кодом 'example'. При этом, мы также хотим добавить новую запись в другую таблицу - AnotherTable
.
В этом кусочке кода транзакция начинается, операции выполняются, и если что-то идет не так, мы можем легко и безопасно откатить все изменения.
<?php
$application = \Bitrix\Main\Application::getInstance();
$connection = $application->getConnection(); // Получаем соединение с базой данных
try {
// Начинаем транзакцию
$connection->startTransaction();
// Получаем из сущности некий объект
$object = \Example\ExampleTable::query()
->where('CODE', 'example')
->addSelect('NAME')
->fetchObject();
if ($object) {
$object->set('NAME', 'Пример записи'); // Меняем поле `NAME` у объекта
$result = $object->save(); // Сохраняем
if (!$result->isSuccess()) {
throw new \Bitrix\Main\SystemException('Ошибка в процессе сохранения данных.');
}
// Пробуем добавить второй элемент в другую таблицу
$anotherObject = \Example\AnotherTable::createObject();
$anotherObject->set('TITLE', 'New title');
$result = $anotherObject->save(); // Сохраняем
if (!$result->isSuccess()) {
// В случае ошибки откатываем транзакцию, и первый элемент не сохранится
throw new \Bitrix\Main\SystemException('Ошибка в процессе сохранения данных.');
}
// Успешно завершаем транзакцию
$connection->commitTransaction();
} else {
throw new \Bitrix\Main\SystemException('Объект не найден.');
}
} catch (\Throwable $e) {
// Если произошла ошибка, отменяем транзакцию
$connection->rollbackTransaction();
throw $e;
}
Волшебство становится еще увлекательнее с появлением вложенных транзакций. Давайте еще усложним пример, который покажет, как они работают.
В случае ошибки во вложенной транзакции, она может быть отменена, сохраняя при этом изменения в более высокоуровневой транзакции или полностью откатываясь, сохраняя целостность данных.
<?php
$application = \Bitrix\Main\Application::getInstance();
$connection = $application->getConnection();
try {
// Начинаем транзакцию
$connection->startTransaction();
// Получаем из сущности некий объект
$object = \Example\ExampleTable::query()
->where('CODE', 'example')
->addSelect('NAME')
->fetchObject();
if ($object) {
$object->set('NAME', 'Пример записи'); // Меняем поле `NAME` у объекта
$result = $object->save(); // Сохраняем
if (!$result->isSuccess()) {
throw new \Bitrix\Main\SystemException('Ошибка в процессе сохранения данных.');
}
// Пробуем добавить второй элемент в другую таблицу
$anotherObject = \Example\AnotherTable::createObject();
$anotherObject->set('TITLE', 'New title');
$result = $anotherObject->save(); // Сохраняем
if (!$result->isSuccess()) {
// В случае ошибки откатываем транзакцию, и первый элемент не сохранится
throw new \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 {
throw new \Bitrix\Main\SystemException('Объект не найден.');
}
} catch (\Bitrix\Main\DB\TransactionException $e) {
// ROLLBACK вложенной транзакции
// Тут мы можем решить, что делать, если вложенная транзакция не прошла
} catch (\Throwable $e) {
// Если произошла ошибка, отменяем транзакцию
$connection->rollbackTransaction();
throw $e;
}
? Что делают методы управления транзакциями?
$connection->startTransaction();
: Этот метод начинает транзакцию, позволяя группировать несколько операций в единое целое.$connection->commitTransaction();
: Вызов этого метода фиксирует все изменения, сделанные в рамках транзакции, и отправляет их в базу данных.$connection->rollbackTransaction();
: Если произошла ошибка или необходимо отменить все изменения в рамках транзакции, этот метод откатывает все операции.
?️?️ Дополнительные тайны:
Транзакции применимы не только к
save()
, но и к другим методам ORM, таким какupdate()
,add()
. А также, к SQL запросам через$connection->query()
Если хотите углубиться в тайны магии транзакций, загляните в официальную документацию Bitrix
? Завершение:
Таким образом, мы научились использовать волшебство транзакций в Bitrix, обеспечивая целостность данных. Если у вас есть свои волшебные методы или вопросы, делитесь в комментариях!