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