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

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

Транзакция в 1С: что это и как с ней работать

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

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

Транзакции работают на двух уровнях. Первый — автоматические транзакции, которые платформа создаёт сама при записи объекта, проведении документа или выполнении пакета запросов. Второй — явные транзакции, которые разработчик открывает и закрывает в коде встроенного языка методами НачатьТранзакцию(), ЗафиксироватьТранзакцию() и ОтменитьТранзакцию(). Понимание обоих уровней необходимо, потому что многие ошибки — взаимоблокировки, конфликты блокировок, потерянные данные — возникают именно на стыке неявного и явного управления.

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

Принципы работы транзакций в 1С

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

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

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

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

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

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

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

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

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

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

bsl
НачатьТранзакцию();
Попытка
    КонтрагентОбъект.Записать();
    ДоговорОбъект.Записать();
    ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ИнформацияОбОшибке = ИнформацияОбОшибке();
    ЗаписьЖурналаРегистрации("ЗагрузкаДанных",
        УровеньЖурналаРегистрации.Ошибка, , ,
        ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
    ВызватьИсключение КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
КонецПопытки;

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

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

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

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

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

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

Транзакции и блокировки: как избежать конфликтов

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

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

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

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

Как проверить и диагностировать проблемы с транзакциями

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

На уровне кластера серверов 1С консоль администрирования позволяет увидеть активные сеансы и соединения, удерживающие блокировки. Длительная транзакция обычно видна как соединение с большим временем вызова СУБД. На уровне самой СУБД (MS SQL, PostgreSQL) доступны системные представления активных запросов и блокировок.

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

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

Журнал регистрации после массовой обработки
Норма

Нет ошибок конфликтов блокировок и отменённых транзакций

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

Повторяющиеся ошибки TLOCK/конфликтов — транзакции слишком длинные или конкурирующие

Состояние данных после сбоя посередине обработки
Норма

Нет частично созданных объектов: либо весь пакет есть, либо его нет

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

Контрагент создан, договор нет — транзакция не охватывала все операции

Активные сеансы в консоли кластера
Норма

Время вызова СУБД у соединений в разумных пределах

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

Соединение с аномально долгим вызовом — вероятный держатель блокировки

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Нужна ли явная транзакция внутри ОбработкаПроведения?

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

Как узнать, какой сеанс держит блокировку?

Откройте консоль кластера серверов 1С и посмотрите активные соединения с длительным временем вызова СУБД. Для точного анализа включите технологический журнал с событиями TLOCK и TDEADLOCK — там видны таблицы и сеансы-участники конфликта.

Что делать, если массовая обработка постоянно откатывается с ошибкой?

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