При разработке бизнес-логики проведения документов в платформе 1С:Предприятие начинающие разработчики часто задаются вопросом: если в процедуре ОбработкаПроведения часть движений уже сформирована, но затем сработало условие проверки и переменная Отказ получила значение Истина, останутся ли в базе данных уже созданные записи регистров?
Рассмотрим подробно, как платформа 1С обрабатывает запись данных, что происходит с движениями регистров на уровне СУБД, а также разберем технические нюансы работы транзакций и оперативной памяти.
Главный механизм, обеспечивающий целостность данных в 1С — это транзакция СУБД. Запись и проведение любого документа всегда выполняются внутри единой транзакции.
Транзакция — это минимальная логически осмысленная операция над базой данных, которая выполняется по принципу «все или ничего». Это означает, что все изменения, произведенные внутри процедуры ОбработкаПроведения (изменение статуса проведения документа, запись в накопительные, сведений или периодические регистры), фиксируются в базе данных только в том случае, если вся процедура отработала успешно и параметр Отказ остался равен Ложь.
Разберем типичный пример кода из процедуры проведения:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Формируем движение по регистру
Движение = Движения.ОстаткиНоменклатуры.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Номенклатура = СсылкаНаТовар;
Движение.Количество = 10;
// Выполняем какую-либо проверку остатков или бизнес-логики
Если НедостаточноТовараНаСкладе Тогда
Сообщить("Недостаточно товара на складе!");
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Проанализируем эту ситуацию: несмотря на то, что строчка создания движения находится выше проверки условия, при взведении Отказ = Истина СУБД выполняет полную отмену изменений (ROLLBACK). Ни документ, ни созданное движение по регистру ОстаткиНоменклатуры не будут сохранены в базе данных.
Выясним, что происходит, если документ перепроводится не в первый раз. В свойствах конфигурации для документов обычно настроен автоматический режим удаления движений. В этом случае перед вызовом процедуры ОбработкаПроведения платформа очищает ранее записанные движения этого документа внутри транзакции.
Если во время повторного проведения взводится флаг Отказ = Истина, транзакция откатывается к своему первоначальному состоянию. Это означает, что старые движения документа будут полностью восстановлены в СУБД в том виде, в котором они существовали до начала перепроведения.
Посмотрим на более сложный сценарий, когда разработчик явно вызывал метод записи набора записей, например Движения.ИмяРегистра.Записать() или Движения.Записать() до того, как установить Отказ = Истина.
При явном вызове метода Записать() внутри процедуры ОбработкаПроведения платформа транслирует сформированные строки в таблицы СУБД и накладывает соответствующие блокировки. Однако эти изменения все еще находятся внутри незавершенной транзакции. Если далее по коду установка Отказ = Истина отменяет транзакцию, СУБД аннулирует абсолютно все записи, включая те, для которых метод Записать() вызвался явно.
При этом стоит учитывать техническую деталь: при явном вызове Движения.ИмяРегистра.Записать() свойство Записывать у конкретного набора записей не сбрасывается автоматически в значение Ложь, в отличие от группового вызова Движения.Записать().
Важно различать данные в базе СУБД и данные в оперативной памяти сервера 1С:
Проведен (он остается Ложь), а также сбрасывает ссылки и номера, если документ был новым.Обратим внимание на важное исключение из общего транзакционного механизма. Записи, создаваемые через программный метод ЗаписьЖурналаРегистрации(), выполняются вне физической транзакции базы данных.
Если внутри процедуры ОбработкаПроведения вы выполняете запись в журнал регистрации, а затем транзакция отменяется с помощью Отказ = Истина или по причине аварийного исключения, событие в журнале регистрации все равно сохранится. Это позволяет фиксировать ошибки и причины отменяемых проведения документов.
Проанализируем влияние размещения проверок на быстродействие системы. С момента открытия транзакции проведения и до момента ее закрытия (отката) платформа и СУБД удерживают блокировки на обновляемые таблицы.
Если проверка условий, приводящих к Отказ = Истина, выполняется в самом конце процедуры (после тяжелых запросов, чтения остатков и формирования тысяч строк движений), СУБД будет удерживать блокировки всё это время, замедляя работу других пользователей.
Рекомендуется придерживаться следующих правил при написании кода проведение:
ОбработкаПроведения до выполнения ресурсоемких запросов и алгоритмов.Отказ = Истина и вызывать оператор Возврат.