Отменится ли вся транзакция в 1С, если один из десяти документов не провелся?

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

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

Принцип атомарности транзакции

Рассмотрим основы работы платформы. Транзакция в 1С (как и в любой классической СУБД) обладает свойством атомарности: это неделимая операция, которая либо выполняется полностью, либо не выполняется вовсе. Если вы открыли транзакцию и начали проводить внутри неё 10 документов, система воспринимает это как единое целое.

Выясним главную особенность: если при проведении хотя бы одного документа возникнет ошибка (например, нехватка остатков, нарушение уникальности номера или программное исключение), транзакция помечается платформой как "битая" (broken). С этого момента никакие данные в базу в рамках этой транзакции записаны быть не могут. Даже если вы перехватите ошибку с помощью конструкции Попытка — Исключение, попытка зафиксировать транзакцию в конце приведет к системному сообщению: "В данной транзакции уже происходили ошибки".

Разберем разницу между «Отказом» и «Исключением»

Проанализируем два сценария, которые часто путают начинающие разработчики:

  1. Логическая ошибка (Отказ = Истина): Если в обработчике ОбработкаПроведения система устанавливает значение Отказ = Истина, это автоматически приводит к тому, что текущая транзакция записи документа не может быть завершена успешно. При вызове метода Записать(РежимЗаписиДокумента.Проведение) это инициирует исключение, которое нужно обрабатывать.
  2. Техническая ошибка (Exception): Ошибки СУБД (блокировки, таймауты) или деление на ноль в коде. Они немедленно прерывают выполнение кода и переводят состояние транзакции в невалидное.

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

Правильный паттерн использования Попытка — Исключение

Посмотрим на классическую ошибку и правильный вариант написания кода, рекомендованный стандартами разработки 1С (ИТС). Очень важно соблюдать последовательность команд открытия транзакции и блока обработки исключений.

Неправильно:


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

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

Правильно (согласно стандартам):


НачатьТранзакцию();
Попытка
    // Проведение документов
    // ...
    ЗафиксироватьТранзакцию();
Исключение
    Если ТранзакцияАктивна() Тогда
        ОтменитьТранзакцию();
    КонецЕсли;
    // Важно пробросить исключение дальше или записать в лог
    ЗаписатьЛогОшибок(ОписаниеОшибки()); 
КонецПопытки;

Как реализовать проведение 10 документов, чтобы «выжили» успешные?

Если ваша задача — провести как можно больше документов из списка, не прерывая процесс из-за одного проблемного, использование одной общей транзакции вам не подходит. В этом случае транзакция должна создаваться индивидуально для каждого документа внутри цикла.

Рассмотрим алгоритм устойчивой пакетной обработки:


Для Каждого ДокументСсылка Из СписокДокументов Цикл
    НачатьТранзакцию();
    Попытка
        ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
        ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
        ЗафиксироватьТранзакцию();
    Исключение
        // Если этот документ не провелся, откатываем только его изменения
        Если ТранзакцияАктивна() Тогда
            ОтменитьТранзакцию();
        КонецЕсли;
        
        // Сообщаем пользователю или пишем в журнал регистрации
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
            СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
                "Документ %1 не проведен по причине: %2", 
                ДокументСсылка, 
                ОписаниеОшибки()
            )
        );
    КонецПопытки;
КонецЦикла;

В данном примере ошибка в одном документе никак не повлияет на результат проведения других. Каждый документ фиксируется в базе независимо.

Почему «длинные» транзакции — это опасно?

Посмотрим на ситуацию со стороны производительности. Проведение большого количества документов (даже если их всего 10, но они «тяжелые») в одной транзакции создает ряд проблем:

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

Особенности вложенных транзакций

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

Помните: если вы получили сообщение "В данной транзакции уже происходили ошибки", это верный признак того, что в коде где-то была проглочена ошибка через пустой блок Исключение, но транзакция при этом не была явно отменена командой ОтменитьТранзакцию(). Платформа 1С строго следит за тем, чтобы «битые» данные не попали в базу, поэтому единственный выход в такой ситуации — полный откат всей цепочки изменений.

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

← На главную