Почему отмена транзакции в 1С не меняет значения локальных переменных?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке программного кода в платформе 1С:Предприятие начинающие разработчики часто сталкиваются с ситуацией, когда после выполнения процедуры ОтменитьТранзакцию() значения обычных переменных не возвращаются к состоянию, которое было до вызова НачатьТранзакцию(). Проанализируем эту ситуацию, выясним причину такого поведения платформы и рассмотрим правильные способы управления данными при откате транзакций.

Анализ ситуации на примере кода

Рассмотрим пример кода, в котором возникает рассматриваемый вопрос:


Переменная1 = 1;
Переменная2 = 0;

НачатьТранзакцию();

Переменная2 = 100;

Если ТранзакцияАктивна() Тогда
    Если Переменная1 = 1 Тогда
        Сообщить("отмена");
        ОтменитьТранзакцию();
    Иначе
        ЗафиксироватьТранзакцию();
    КонецЕсли;
КонецЕсли;

Сообщить(Строка(Переменная1) + " " + Переменная2);

В данном примере ожидается, что после отмены транзакции в окне сообщений зафиксируется значение "1 0". Однако платформа выводит "1 100". Возникает вопрос: почему значение Переменная2 осталось равным 100?

Почему транзакция не отменяет изменения переменных в памяти

Разберем по шагам, как устроена работа транзакций в 1С. Функция транзакции заключается исключительно в обеспечении целостности данных базы данных (СУБД). Платформа 1С отслеживает и откатывает при вызове ОтменитьТранзакцию() только те операции, которые записывают или изменяют таблицы в базе данных (записи регистров, создание и изменение документов, справочников и т. д.).

Локальные переменные встроенного языка (числа, строки, булево), а также прикладные объекты и коллекции, находящиеся в оперативной памяти сервера или клиента, не входят в транзакционный контекст СУБД. Изменение значения локальной переменной внутри блока транзакции изменяет ячейку в оперативной памяти компьютера. Когда вызывается ОтменитьТранзакцию(), СУБД отменяет изменения в таблицах базы данных, но оперативная память остается в текущем («грязном») состоянии.

Поведение объектов базы данных в оперативной памяти

Посмотрим, как транзакции влияют на объекты СУБД, такие как СправочникОбъект или ДокументОбъект:

  1. Изменение реквизитов объекта в памяти: Если внутри транзакции поменять реквизит объекта (например, ДокументОбъект.Сумма = 500), значение изменится в оперативной памяти. Если затем вызвать ОтменитьТранзакцию(), запись объекта в БД будет отменена, но реквизит объекта в оперативной памяти сохранит измененное значение.
  2. Чтение через ссылку: Если после отмены транзакции обратиться к данным через ссылку (ДокументСсылка.Сумма), платформа выполнит считывание из базы данных и вернет исходное значение до начала транзакции.
  3. Сброс к состоянию базы данных: Чтобы вернуть свойства объекта в памяти к актуальному состоянию из БД, необходимо явно вызвать метод Прочитать().

Как правильно реализовывать откат значений вручную

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

  1. Сохранение значений во буферные переменные:

    Для простых типов данных (числа, строки, даты, булево) перед вызовом НачатьТранзакцию() запоминают исходные значения во временные переменные. В случае ошибки или отмены транзакции исходные значения восстанавливаются вручную.

    
    Переменная2 = 0;
    БуферПеременная2 = Переменная2; // Сохраняем исходное значение
    
    НачатьТранзакцию();
    Попытка
        Переменная2 = 100;
        
        // Какая-то логика с возможным откатом
        Если НеобходимОткат Тогда
            ВызватьИсключение "Требуется отмена";
        КонецЕсли;
        
        ЗафиксироватьТранзакцию();
    Исключение
        ОтменитьТранзакцию();
        Переменная2 = БуферПеременная2; // Восстанавливаем значение вручную
        Сообщить("Транзакция отменена. Значение восстановлено: " + Переменная2);
    КонецПопытки;
    
  2. Копирование сложных коллекций:

    Если внутри транзакции меняются данные сложных структур (например, ТаблицаЗначений, Структура или Соответствие), создают их копии перед началом транзакции с помощью метода Скопировать().

    
    КопияТаблицы = ИсходнаяТаблица.Скопировать();
    
    НачатьТранзакцию();
    Попытка
        // Изменение строк в ИсходнаяТаблица
        
        ЗафиксироватьТранзакцию();
    Исключение
        ОтменитьТранзакцию();
        ИсходнаяТаблица = КопияТаблицы.Скопировать(); // Откат коллекции
    КонецПопытки;
    

Таким образом, важно четко разделять данные в оперативной памяти и данные в базе данных. Механизм транзакций в 1С отвечает только за физическое состояние таблиц базы данных, а актуальность переменных в коде лежит целиком на разработчике.

← На главную