Разработка и Конфигурация · 11 мин
Как работает транзакция в 1С: механизм и практика применения
Как работает транзакция в 1С: НачатьТранзакцию, ЗафиксироватьТранзакцию, ОтменитьТранзакцию, уровни изоляции, блокировки и типичные ошибки разработчика.
Транзакция в 1С — это последовательность операций с базой данных, которая выполняется целиком или не выполняется вовсе. Если внутри транзакции происходит ошибка, платформа откатывает все изменения, внесённые с её начала, и база остаётся в согласованном состоянии. Это фундаментальный механизм, обеспечивающий целостность учётных данных: проведение документа, запись набора регистров и изменение справочника либо фиксируются вместе, либо не сохраняются вообще.
Платформа 1С:Предприятие использует транзакции на двух уровнях. Во-первых, многие операции неявно обёрнуты в транзакции самой платформой — например, проведение документа или обмен данными. Во-вторых, разработчик может управлять транзакциями явно через методы встроенного языка НачатьТранзакцию(), ЗафиксироватьТранзакцию() и ОтменитьТранзакцию(). Понимание того, как эти уровни взаимодействуют, критично для написания надёжного кода.
Ошибки в работе с транзакциями — одна из главных причин конфликтов блокировок, взаимоблокировок и «зависающих» сеансов в многопользовательских базах. Ниже разобраны механизм работы, правила вложенности, управляемые блокировки и практические сценарии с примерами кода.
Что такое транзакция и зачем она нужна в 1С
Транзакция реализует принцип «всё или ничего». Классический пример — проведение документа реализации: нужно списать товар со склада, сформировать движения по регистрам продаж и задолженности. Если после записи первого регистра произойдёт сбой, без транзакции в базе останутся «оборванные» данные: товар списан, а задолженность не отражена. Транзакция исключает такое рассогласование.
Транзакции в 1С подчиняются классическим свойствам ACID на уровне СУБД: атомарность, согласованность, изолированность и долговечность. Практически для разработчика важнее всего атомарность (откат при ошибке) и изолированность (что видят другие пользователи, пока транзакция не завершена).
Важно понимать, что транзакция работает только с данными информационной базы. Действия с файловой системой, отправка HTTP-запросов или записей во внешние источники не откатываются. Если внутри транзакции вы отправили письмо или записали файл, а затем транзакция отменилась — внешнее действие останется выполненным, что нередко становится источником рассинхронизации.
Явное управление: НачатьТранзакцию, ЗафиксироватьТранзакцию, ОтменитьТранзакцию
Явная транзакция открывается методом НачатьТранзакцию(). Все изменения данных после этого вызова попадают в контекст транзакции. Метод ЗафиксироватьТранзакцию() подтверждает изменения, а ОтменитьТранзакцию() откатывает их. Стандартный шаблон выглядит так:
НачатьТранзакцию();
Попытка
// изменение данных
НовыйОбъект.Записать();
НаборЗаписей.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение ОписаниеОшибки();
КонецПопытки;
Ключевые правила этого шаблона: отмена транзакции выполняется в блоке Исключение до повторного вызова исключения, а фиксация — только после успешного завершения всех операций. Если забыть ВызватьИсключение после отмены, вызывающий код не узнает об ошибке и продолжит работу как ни в чём не бывало — это одна из самых коварных ошибок.
Проверить, находится ли код внутри транзакции, можно функцией ТранзакцияАктивна(). Она полезна в универсальных процедурах, которые могут вызываться как из транзакционного, так и из обычного контекста.
Вложенные транзакции и неявные транзакции платформы
1С поддерживает вложенные вызовы НачатьТранзакцию(), но с важной особенностью: реально существует только одна транзакция на уровне СУБД. Вложенные вызовы лишь увеличивают счётчик. Внутренний ЗафиксироватьТранзакцию() не фиксирует данные физически — фиксация произойдёт только при закрытии самой внешней транзакции. А вот ОтменитьТранзакцию() на любом уровне вложенности откатывает всю внешнюю транзакцию целиком.
Это означает, что нельзя «откатить только часть» работы через вложенную транзакцию. Если процедура внутри транзакции вызывает ОтменитьТранзакцию(), будут потеряны и изменения, сделанные до её вызова. Такое поведение нужно учитывать при проектировании библиотечных процедур.
Кроме явных транзакций, платформа сама открывает неявные: при проведении документа (весь обработчик ОбработкаПроведения и запись движений выполняются в одной транзакции), при записи объекта в транзакции обмена данными, при загрузке данных планов обмена. Если ваш код вызывается из обработчика проведения, он уже находится внутри транзакции, и дополнительная явная транзакция будет вложенной.
Блокировки и изоляция: почему транзакции конфликтуют
Пока транзакция изменяет данные, СУБД ставит на эти данные блокировки, чтобы другие сеансы не прочитали промежуточное состояние и не изменили те же строки. В клиент-серверном варианте 1С работает в режиме управляемых блокировок: разработчик и платформа явно указывают, какие данные блокируются и как — через метод БлокировкаДанных или автоматически при проведении и записи.
Типичный сценарий конфликта: два пользователя одновременно проводят документы, списывающие один и тот же товар со склада. Первая транзакция блокирует записи регистра остатков, вторая ждёт освобождения. Если ожидание превышает таймаут СУБД, пользователь получает ошибку «Конфликт блокировок при выполнении транзакции». Хуже ситуация со взаимоблокировкой (deadlock): транзакция А держит ресурс 1 и ждёт ресурс 2, транзакция Б — наоборот. СУБД принудительно откатывает одну из них.
Практические способы снижения конфликтов: блокировать данные в одном и том же порядке во всех процедурах, минимизировать время жизни транзакции, не выполнять внутри транзакции длительные расчёты и обращения к внешним системам, использовать разделители итогов и режим разделения итогов при проведении. Для массовых обработок полезно фиксировать транзакции порциями, а не одной гигантской транзакцией на всю выборку.
Практические сценарии использования
Массовая обработка с порционной фиксацией
При обработке большой выборки разумно фиксировать каждый объект (или пакет объектов) в отдельной транзакции. Тогда ошибка в одном элементе не откатит уже обработанные, а журнал ошибок позволит повторить только проблемные объекты. Для неидемпотентных операций ведите учёт обработанных элементов, чтобы повторный запуск не задвоил данные.
Гарантированная пара «документ + регистр»
Если документ вручную (не через проведение) должен записываться вместе с движениями по регистру, обе операции нужно объединить в явную транзакцию. Иначе при сбоях возможны документы без движений или движения без документа. Тот же принцип действует при записи связанных объектов: заказ и его резервы, контрагент и его счета.
Интерактивные действия пользователя
Осторожно открывайте транзакции в клиентском коде или в обработчиках, ожидающих ввода пользователя. Транзакция, открытая до диалога с пользователем и закрытая после ответа, держит блокировки всё время раздумий — это прямой путь к массовым конфликтам. Сначала соберите все данные, затем откройте транзакцию и выполните запись максимально быстро.
- 1Подготовьте и проверьте все данные до открытия транзакции.
- 2Вызовите НачатьТранзакцию().
- 3В блоке Попытка выполните изменения и вызовите ЗафиксироватьТранзакцию().
- 4В блоке Исключение вызовите ОтменитьТранзакцию(), затем ВызватьИсключение с описанием ошибки.
- 5Проверьте результат: данные записаны целиком либо отсутствуют полностью, в журнале регистрации есть запись об ошибке при сбое.
Как проверить корректность работы транзакционного кода
Минимальная проверка — смоделировать ошибку внутри транзакции (например, временно вызвать исключение после первой записи) и убедиться, что в базе не осталось частичных изменений. Вторая проверка — параллельный запуск: выполните операцию одновременно в двух сеансах и убедитесь, что данные не дублируются и конфликты обрабатываются осмысленным сообщением, а не «падением» сеанса.
Для анализа блокировок в клиент-серверном варианте используются технологический журнал (события TLOCK, TDEADLOCK, TTIMEOUT) и средства СУБД. По журналу можно определить, какие объекты конфликтуют и какие процедуры держат транзакции слишком долго.
Как проверить результат
После исключения в базе нет ни одной из изменённых записей
Часть объектов записана, часть нет — транзакция не охватывает все операции
Второй сеанс ждёт или получает понятную ошибку конфликта
Дублирование данных или взаимоблокировки в технологическом журнале
Между началом и фиксацией только запись данных
Внутри транзакции расчёты, запросы к внешним системам, диалоги с пользователем
Часто задаваемые вопросы
Откатывает ли ОтменитьТранзакцию только вложенный уровень?
Нет. В 1С физически существует одна транзакция, а вложенные вызовы лишь меняют счётчик. Отмена на любом уровне вложенности откатывает все изменения внешней транзакции. Фиксация же реально происходит только при закрытии самого внешнего уровня.
Нужно ли явно открывать транзакцию при проведении документа?
Обычно нет: платформа уже выполняет обработчик проведения и запись движений внутри системной транзакции. Явная транзакция в этом контексте будет вложенной и не даст дополнительной защиты, но усложнит диагностику ошибок.
Что делать при постоянных ошибках «Конфликт блокировок»?
Сократите время жизни транзакций, унифицируйте порядок блокировки объектов во всех процедурах, вынесите длительные расчёты за пределы транзакции и проанализируйте технологический журнал по событиям TLOCK и TDEADLOCK, чтобы найти конкретные конфликтующие объекты.
Откатятся ли файлы или отправленные письма при отмене транзакции?
Нет. Транзакция контролирует только данные информационной базы. Записанные файлы, HTTP-запросы и письма остаются выполненными, поэтому такие действия следует выносить за пределы транзакции или выполнять после успешной фиксации.
Как узнать в коде, активна ли транзакция?
Используйте функцию ТранзакцияАктивна(). Она возвращает Истина, если код выполняется внутри транзакции — явной или открытой платформой. Это полезно в универсальных процедурах, которые не должны сами управлять транзакциями, если уже находятся внутри чужой.
Можно ли зафиксировать часть изменений, а часть откатить?
Средствами одной транзакции — нет, она атомарна целиком. Если нужна частичная фиксация, разбейте работу на несколько последовательных транзакций, каждая из которых фиксирует логически завершённую порцию данных.
Что важно запомнить
Транзакция в 1С гарантирует атомарность изменений: всё фиксируется или всё откатывается. Используйте шаблон «НачатьТранзакцию — Попытка — Зафиксировать / Исключение — Отменить — ВызватьИсключение», помните, что вложенная отмена откатывает всю внешнюю транзакцию, держите транзакции короткими и не выполняйте внутри них действия, которые нельзя откатить.