Что блокируется при вызове НачатьТранзакцию в 1С и почему падает производительность?

Программист IT и автоматизация бизнеса
← На главную

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

Что происходит при старте транзакции?

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

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


НачатьТранзакцию();
Попытка
    // Обработка множества документов
    ДокументОбъект1.Записать(РежимЗаписиДокумента.Проведение);
    ДокументОбъект2.Записать(РежимЗаписиДокумента.Проведение);
    
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    Сообщить("Произошла ошибка, изменения отменены.");
КонецПопытки;

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

Различие автоматических и управляемых блокировок

Посмотрим на то, как платформа и СУБД управляют блокировками. Поведение системы кардинально зависит от режима работы базы:

  1. Автоматический режим блокировок: В этом классическом режиме любое чтение объекта из базы приводит к установке блокировки на чтение, а любое изменение — к блокировке на запись. Если транзакция прочитала данные, другая транзакция не сможет их изменить до завершения первой. Если транзакция изменила данные (наложила блокировку на запись), другие пользователи не смогут даже прочитать эти данные (будут висеть в ожидании). Это часто приводит к DeadLock (взаимоблокировкам) и падению системы по таймауту.
  2. Управляемый режим блокировок (Версионирование): В современных базах 1С (при использовании MS SQL Server с включенным RCSI или PostgreSQL с MVCC) работает механизм версионирования. В этом случае чтение данных не блокирует их изменение другими сеансами. Более того, изменение данных одной транзакцией не мешает другим пользователям параллельно читать старую (последнюю подтвержденную) версию этих данных. В управляемом режиме блокировки контролируются сервером 1С на логическом уровне, а не на уровне СУБД.

Почему блокируется вся таблица и пользователи не могут работать?

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

Чтобы сэкономить ресурсы оперативной памяти сервера, система автоматически повышает уровень блокировки от отдельных строк до всей таблицы целиком. В управляемом режиме 1С это происходит по умолчанию, если в рамках одной транзакции на одно пространство блокировок (например, на один регистр накопления) накладывается более 100 000 блокировок. На уровне СУБД (в автоматическом режиме) пороги еще ниже — SQL Server может заблокировать всю таблицу при блокировке около 5 000 строк.

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

Рекомендации: как избежать проблем с транзакциями

Проанализируем шаги, которые помогут вам оптимизировать работу с транзакциями и избежать блокировки работы пользователей:

  1. Дробите транзакции: Никогда не помещайте обработку тысяч документов в одну глобальную транзакцию. Разбивайте их на порции (батчи) по 50-100 штук.
  2. Используйте явное указание режима: Вызов НачатьТранзакцию() поддерживает параметр, которым можно явно задать режим. Используйте управляемые блокировки там, где это возможно.

    
    НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);
    // ваш код
    ЗафиксироватьТранзакцию();
    
  3. Учитывайте потребление памяти (rphost): Длительные транзакции не только блокируют данные, но и занимают оперативную память на сервере приложений 1С. Все кешированные изменения данных до вызова ЗафиксироватьТранзакцию() хранятся в ОЗУ процесса rphost. Слишком объемная транзакция может "съесть" всю память кластера.
  4. Помните про вложенность транзакций: В 1С транзакции не имеют реальной вложенности. Если внутри транзакции открывается еще одна, то ошибка во внутренней транзакции неизбежно приведет к откату всей внешней транзакции с системным сообщением "В данной транзакции уже происходили ошибки".
  5. Отличайте пессимистические блокировки: Транзакционные блокировки возникают в момент программной работы с БД (на доли секунды). Если же пользователь открыл форму документа и начал его редактировать (появилась "звездочка"), платформа накладывает пессимистическую блокировку объекта. Она не требует вызова метода транзакции и держится до закрытия формы или сохранения объекта, не пуская других пользователей к редактированию именно этого документа.

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

← На главную