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