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

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

Выполнить в транзакции 1С: что это значит и как применять

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

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

Механизм транзакций встроен в платформу 1С и работает поверх транзакций СУБД (MS SQL Server, PostgreSQL, файловой базы). Разработчику доступны методы глобального контекста НачатьТранзакцию(), ЗафиксироватьТранзакцию() и ОтменитьТранзакцию(), а также автоматические транзакции, которые платформа открывает сама при записи и проведении документов.

Что такое транзакция в 1С и зачем она нужна

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

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

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

Базовый синтаксис: НачатьТранзакцию, ЗафиксироватьТранзакцию, ОтменитьТранзакцию

Управление транзакциями в явном виде выполняется тремя методами глобального контекста. Стандартный шаблон кода выглядит так:

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

Попытка

// операции с данными: запись объектов, проведение документов

Документ.Записать(РежимЗаписиДокумента.Проведение);

РегистрыНакопления.ОстаткиТоваров.ЗаписатьНабор(НаборЗаписей);

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

Исключение

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

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

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

Ключевые правила этого шаблона:

  • Метод НачатьТранзакцию() открывает транзакцию. До вызова ЗафиксироватьТранзакцию() изменения видны только внутри текущего сеанса и могут быть отменены.
  • ЗафиксироватьТранзакцию() применяет все накопленные изменения. После фиксации откат невозможен.
  • ОтменитьТранзакцию() откатывает все изменения, сделанные с момента начала транзакции.
  • Блок Попытка/Исключение обязателен: без него при ошибке транзакция останется «висеть» незавершённой, что приведёт к блокировкам данных.

Автоматические транзакции платформы

Во многих случаях платформа 1С открывает транзакцию сама, и явный вызов НачатьТранзакцию() не нужен. Автоматические транзакции возникают при:

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

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

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

Когда явная транзакция необходима, а когда вредна

Явная транзакция оправдана, если логика требует, чтобы несколько независимых операций записи либо выполнились все, либо не выполнилась ни одна. Типичные сценарии: загрузка данных из файла с записью нескольких связанных объектов, обмен данными, «разнесение» одного документа с корректировкой связанных.

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

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

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

Нужно атомарно записать несколько связанных объектовИспользуйте явную транзакцию с Попытка/Исключение
Только проводится один документЯвная транзакция не нужна — платформа делает это автоматически
Обрабатывается большой массив независимых строкФиксируйте транзакцию порциями, а не одной общей
Нужно откатить часть уже записанногоЭто невозможно — пересмотрите границы транзакции до записи

Вложенные транзакции и уровни

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

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

ТранзакцияОткрытаЗдесь = Не ТранзакцияАктивна();

Если ТранзакцияОткрытаЗдесь Тогда

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

КонецЕсли;

Попытка

// работа с данными

Если ТранзакцияОткрытаЗдесь Тогда

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

КонецЕсли;

Исключение

Если ТранзакцияОткрытаЗдесь Тогда

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

КонецЕсли;

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

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

Блокировки и конфликты в многопользовательском режиме

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

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

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

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

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

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

Также полезно контролировать длительность транзакций через технологический журнал: события DBMSSQL/DBPOSTGRS с большой длительностью и события TLOCK/TTIMEOUT указывают на проблемные места с блокировками.

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

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

Поведение при ошибке в середине кода
Норма

Все изменения откатились, база в исходном состоянии

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

Часть данных записана — транзакция или обработка исключения отсутствует

Состояние после успешного выполнения
Норма

Все объекты записаны, транзакция закрыта (ТранзакцияАктивна() = Ложь)

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

Транзакция осталась активной — нарушена парность вызовов

Работа других пользователей во время обработки
Норма

Конфликтов блокировок нет или они единичны

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

Массовые ошибки блокировок — транзакция слишком длинная

Практические рекомендации

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

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

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

Итог

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

Транзакция в 1С — механизм «всё или ничего» для группы операций с данными. Используйте НачатьТранзакцию/ЗафиксироватьТранзакцию/ОтменитьТранзакцию в связке с Попытка/Исключение, держите транзакции короткими, помните об автоматических транзакциях платформы и о том, что откат вложенной транзакции отменяет всё.

Частые вопросы о транзакциях в 1С

Чем отличается ЗафиксироватьТранзакцию от ОтменитьТранзакцию?

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

Можно ли откатить только часть изменений внутри транзакции?

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

Что произойдёт, если забыть закрыть транзакцию?

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

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

Нет. Платформа автоматически выполняет проведение документа в транзакции: запись документа и всех движений атомарна. Явная транзакция нужна только если вместе с документом должны атомарно изменяться другие объекты.

Как узнать, открыта ли транзакция в текущем коде?

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

Почему возникает ошибка «Конфликт блокировки при выполнении транзакции»?

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