При разработке программного кода в платформе 1С:Предприятие начинающие разработчики часто сталкиваются с ситуацией, когда после выполнения процедуры ОтменитьТранзакцию() значения обычных переменных не возвращаются к состоянию, которое было до вызова НачатьТранзакцию(). Проанализируем эту ситуацию, выясним причину такого поведения платформы и рассмотрим правильные способы управления данными при откате транзакций.
Рассмотрим пример кода, в котором возникает рассматриваемый вопрос:
Переменная1 = 1;
Переменная2 = 0;
НачатьТранзакцию();
Переменная2 = 100;
Если ТранзакцияАктивна() Тогда
Если Переменная1 = 1 Тогда
Сообщить("отмена");
ОтменитьТранзакцию();
Иначе
ЗафиксироватьТранзакцию();
КонецЕсли;
КонецЕсли;
Сообщить(Строка(Переменная1) + " " + Переменная2);
В данном примере ожидается, что после отмены транзакции в окне сообщений зафиксируется значение "1 0". Однако платформа выводит "1 100". Возникает вопрос: почему значение Переменная2 осталось равным 100?
Разберем по шагам, как устроена работа транзакций в 1С. Функция транзакции заключается исключительно в обеспечении целостности данных базы данных (СУБД). Платформа 1С отслеживает и откатывает при вызове ОтменитьТранзакцию() только те операции, которые записывают или изменяют таблицы в базе данных (записи регистров, создание и изменение документов, справочников и т. д.).
Локальные переменные встроенного языка (числа, строки, булево), а также прикладные объекты и коллекции, находящиеся в оперативной памяти сервера или клиента, не входят в транзакционный контекст СУБД. Изменение значения локальной переменной внутри блока транзакции изменяет ячейку в оперативной памяти компьютера. Когда вызывается ОтменитьТранзакцию(), СУБД отменяет изменения в таблицах базы данных, но оперативная память остается в текущем («грязном») состоянии.
Посмотрим, как транзакции влияют на объекты СУБД, такие как СправочникОбъект или ДокументОбъект:
ДокументОбъект.Сумма = 500), значение изменится в оперативной памяти. Если затем вызвать ОтменитьТранзакцию(), запись объекта в БД будет отменена, но реквизит объекта в оперативной памяти сохранит измененное значение.ДокументСсылка.Сумма), платформа выполнит считывание из базы данных и вернет исходное значение до начала транзакции.Прочитать().Поскольку встроенный язык не отслеживает значения переменных при отмене транзакций, откат локальных данных разработчику необходимо реализовывать самостоятельно. Рассмотрим подробнее основные подходы к решению этой задачи:
Для простых типов данных (числа, строки, даты, булево) перед вызовом НачатьТранзакцию() запоминают исходные значения во временные переменные. В случае ошибки или отмены транзакции исходные значения восстанавливаются вручную.
Переменная2 = 0;
БуферПеременная2 = Переменная2; // Сохраняем исходное значение
НачатьТранзакцию();
Попытка
Переменная2 = 100;
// Какая-то логика с возможным откатом
Если НеобходимОткат Тогда
ВызватьИсключение "Требуется отмена";
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Переменная2 = БуферПеременная2; // Восстанавливаем значение вручную
Сообщить("Транзакция отменена. Значение восстановлено: " + Переменная2);
КонецПопытки;
Если внутри транзакции меняются данные сложных структур (например, ТаблицаЗначений, Структура или Соответствие), создают их копии перед началом транзакции с помощью метода Скопировать().
КопияТаблицы = ИсходнаяТаблица.Скопировать();
НачатьТранзакцию();
Попытка
// Изменение строк в ИсходнаяТаблица
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ИсходнаяТаблица = КопияТаблицы.Скопировать(); // Откат коллекции
КонецПопытки;
Таким образом, важно четко разделять данные в оперативной памяти и данные в базе данных. Механизм транзакций в 1С отвечает только за физическое состояние таблиц базы данных, а актуальность переменных в коде лежит целиком на разработчике.