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