К статье
Практический материал

Разработка и Конфигурация · 10 мин

Транзакции в 1С: когда использовать и для чего они нужны

Что такое транзакция в 1С, когда её применять в коде, как работают НачатьТранзакцию и ЗафиксироватьТранзакцию, типичные ошибки и вложенные транзакции.

Транзакция в 1С — это механизм, который гарантирует, что группа операций с базой данных будет выполнена либо целиком, либо не выполнится вообще. Если в середине обработки происходит ошибка, платформа откатывает все изменения, и база остаётся в согласованном состоянии. Без транзакций при сбое часть данных может записаться, а часть — нет, что приводит к «битым» документам, расхождениям в остатках и бухгалтерских ошибках.

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

Что такое транзакция и как она работает в 1С

Транзакция — это последовательность операций чтения и записи, которую система управления базами данных рассматривает как неделимую единицу. У транзакции есть ключевые свойства: атомарность (всё или ничего), согласованность (данные не нарушают заданных правил), изоляция (параллельные процессы не видят незавершённые изменения) и надёжность (зафиксированный результат не теряется).

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

Типовой шаблон кода выглядит так:

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

Попытка

// операции записи

ДокументОбъект.Записать();

РегистрНаборЗаписей.Записать();

ЗафиксироватьТранзакцию();

Исключение

ОтменитьТранзакцию();

ВызватьИсключение ОписаниеОшибки();

КонецПопытки;

Когда транзакция нужна обязательно

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

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

Классический пример — обмен данными. Если при загрузке пакета записалась шапка документа, но не записались табличная часть и движения, пользователь получит документ, который выглядит нормально, но искажает отчёты. Транзакция гарантирует: либо документ загрузился полностью, либо его нет вовсе.

Маршрут решения

Как выбрать действие

Операция изменяет два и более объекта или набора записейОборачивайте все записи в одну явную транзакцию
Записывается один объект без связанных измененийЯвная транзакция не нужна — платформа запишет объект атомарно
Выполняется проведение документаНе открывайте свою транзакцию — проведение уже выполняется в транзакции платформы
Идёт массовая обработка тысяч элементовРазбейте работу на транзакции по порциям, а не одну большую транзакцию

Когда транзакция не нужна или вредна

Одиночная запись объекта в 1С уже атомарна: платформа сама открывает и фиксирует транзакцию при вызове Записать(). Оборачивать одну запись в НачатьТранзакцию() бессмысленно — это лишь добавляет вложенность.

Вредна транзакция в нескольких случаях. Во-первых, длинные транзакции: пока транзакция открыта, она удерживает блокировки на затронутых данных, и другие пользователи ждут или получают ошибки блокировок. Обработка, которая в одной транзакции перепроводит тысячи документов, способна парализовать работу базы. Во-вторых, транзакции нельзя растягивать на интерактивные действия — нельзя начать транзакцию, показать пользователю диалог и ждать ответа: соединение с СУБД будет удерживаться всё это время.

Вложенные транзакции и особенности платформы

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

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

Управляемые блокировки и транзакции

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

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

Порядок записи с блокировкой
  1. 1
    Вызовите НачатьТранзакцию()
  2. 2
    Создайте объект БлокировкаДанных и добавьте элементы на нужные регистры или объекты
  3. 3
    Вызовите Блокировка.Заблокировать()
  4. 4
    Прочитайте актуальные данные (остатки, статусы)
  5. 5
    Выполните проверки и запись
  6. 6
    Вызовите ЗафиксироватьТранзакцию()
  7. 7
    В блоке Исключение вызовите ОтменитьТранзакцию() и пробросьте ошибку дальше

Типичные ошибки при работе с транзакциями

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

Типичные ошибки
01
Вызвать ЗафиксироватьТранзакцию() до того, как выполнены все записи — при ошибке после фиксации часть данных уже не откатить
02
Проглотить исключение без ОтменитьТранзакцию() — транзакция остаётся открытой до конца сеанса и держит блокировки
03
Открыть транзакцию и выполнять внутри долгий расчёт или обращение к веб-сервису — растут блокировки и тайм-ауты
04
Одна гигантская транзакция на массовую обработку вместо порционной фиксации — журнал транзакций СУБД раздувается, база тормозит
05
Отмена транзакции в общей процедуре, вызванной из чужого кода, — откатываются и чужие изменения
06
Забыть, что при исключении вне Попытка/Исключение транзакция откатится платформой, но сообщение пользователю будет неинформативным

Как проверить, что транзакция работает правильно

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

Дополнительно стоит проверить поведение под параллельной нагрузкой: запустить обработку в двух сеансах одновременно на одних и тех же данных. Корректный код либо дождётся снятия блокировки, либо выдаст понятную ошибку конфликта, но не запишет расхождения. В технологическом журнале и через консоль СУБД можно убедиться, что транзакции не висят открытыми дольше необходимого.

Контрольные точки

Как проверить результат

Состояние данных после искусственной ошибки внутри транзакции
Норма

Ни одна из операций не записана, данные как до запуска

Тревожный признак

Часть записей сохранилась — транзакция фиксируется преждевременно

Поведение при параллельном запуске
Норма

Второй сеанс ждёт или получает ошибку блокировки, данные согласованы

Тревожный признак

Оба сеанса записали данные с расхождениями

Длительность транзакции в техножурнале
Норма

Транзакция живёт миллисекунды или секунды и содержит только запись

Тревожный признак

Транзакция открыта десятки секунд, внутри расчёты или обращения к сервисам

FAQ по транзакциям в 1С

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

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

Что произойдёт, если забыть вызвать ЗафиксироватьТранзакцию()?

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

Можно ли откатить только часть транзакции?

В 1С нет механизма точек сохранения (savepoints), доступного разработчику на встроенном языке. Отмена транзакции откатывает всё с момента начала внешней транзакции. Если нужно частичное сохранение, разбивайте работу на несколько независимых транзакций и обрабатывайте ошибки на уровне каждой порции.

Как обрабатывать ошибки блокировок при параллельной работе?

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

Влияет ли размер транзакции на производительность?

Да. Чем дольше открыта транзакция и чем больше данных она затрагивает, тем больше блокировок удерживается и тем выше нагрузка на журнал транзакций СУБД. Массовые обработки лучше делить на порции с фиксацией каждой порции, а все тяжёлые вычисления выполнять до открытия транзакции.

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

Транзакция отвечает за целостность: все операции фиксируются или откатываются вместе. Блокировка отвечает за изоляцию от параллельных сеансов: она не даёт другим пользователям изменить или прочитать данные, с которыми вы работаете. Для корректной записи остатков обычно нужны обе: блокировка внутри транзакции.

Итог

Что важно запомнить

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