Нужно ли отменять проведение документа перед его повторным проведением в транзакции 1С?

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

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


НачатьТранзакцию(); 
ДокОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);

// Изменяем реквизиты объекта
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.НеОперативный);
ЗафиксироватьТранзакцию();

Разберем подробно, имеет ли смысл такой подход, защищает ли вызов отмены проведения от параллельного изменения объекта другими пользователями и как эта конструкция влияет на производительность базы данных.

Назначение явной транзакции и разница с блокировками

Рассмотрим частые заблуждения относительно того, зачем нужна эта конструкция:

  1. Блокировка объекта от изменений: Вызов РежимЗаписиДокумента.ОтменаПроведения не является инструментом пессимистической блокировки объекта для других пользователей. За блокировку отвечает вызов метода ДокОбъект.Заблокировать() или механизмы управляемых блокировок (объект БлокировкаДанных). Транзакция лишь накладывает системную блокировку СУБД на время своего выполнения, гарантируя целостность данных.
  2. Атомарность операций: Главная цель вызова НачатьТранзакцию() — обеспечить откат всех изменений в случае возникновения ошибки. Если во время записи или проведения произойдет сбой (аппаратный сбой, отказ в коде, нехватка остатков), вся транзакция откатится, и документ вернется в свое исходное состояние.

Влияние предварительной отмены проведения на производительность

Проанализируем технические процессы, которые запускаются при двойном вызове метода Записать() внутри одной транзакции:

  1. Двойная нагрузка на СУБД: При выполнении метода Записать() сначала в режиме отмены проведения, а затем в режиме проведения платформа дважды выполняет физическую запись в таблицы базы данных. Это приводит к лишним операциям ввода-вывода (I/O) и повторной записи данных в журнал транзакций СУБД (WAL/LDF). На больших объемах данных выполнение алгоритма замедляется примерно в два раза.
  2. Избыточные подписки и события: При вызове отмены проведения платформа инициирует выполнение всей цепочки обработчиков: ПередЗаписью, ОбработкаОтменыПроведения, ПриЗаписи, а также привязанных подписок на события. В типовых конфигурациях при отмене проведения подписки могут сбрасывать независимые регистры сведений или привязаные статусы, которые не всегда корректно восстанавливаются при повторном вызове проведения.
  3. Смещение границ последовательностей: Если документ входит в последовательности документов, предварительное снятие с проведения принудительно сдвигает границу последовательности назад на момент времени этого документа. Это создает лишнюю нагрузку на таблицы последовательностей.

Очистка движений и свойства метаданных

Выясним, нужно ли отменять проведение для очистки старых движений регистра. Логика удаления движений регулируется свойством документа Удаление движений в конфигураторе:

  1. Если установлено значение «Удалять автоматически», платформа самостоятельно очищает все старые движения документа непосредственно перед выполнением процедуры ОбработкаПроведения. В этом случае вызов ОтменаПроведения полностью дублирует штатные механизмы платформы.
  2. Если установлено значение «Удалять автоматически при отмене проведения», движения очищаются платформой при снятии с проведения или удаляются разработчиком вручную в коде модуля документа.

Единственное исключение, когда вызов отмены проведения действительно оправдан — это ситуации, когда в обработке проведения документа выполняется анализ остатков по регистрам, а алгоритм проведении не умеет исключать из выборки собственные текущие движения этого же документа. Однако в типовых конфигурациях (ERP, Комплексная автоматизация, Управление торговлей) учет собственных движений уже заложен в архитектуру.

Оптимальный вариант реализации

Если в конфигурации используется стандартный механизм проведения и нет специфической зависимости алгоритмов от проведения/отмены проведения, предварительный вызов РежимЗаписиДокумента.ОтменаПроведения следует убрать.

Рассмотрим правильный и оптимизированный вариант записи и проведения документа:


// Заботимся о блокировке объекта при необходимости
ДокОбъект.Заблокировать();

НачатьТранзакцию();
Попытка
    // Вносим необходимые изменения в реквизиты
    ДокОбъект.Комментарий = "Изменено автоматически";
    
    // Проводим документ за один шаг
    ДокОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.НеОперативный);
    
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;

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

← На главную