Многие разработчики сталкиваются с ситуацией, когда, казалось бы, изолированные операции над регистром сведений приводят к блокировкам. Рассмотрим подробно, почему платформа 1С:Предприятие 8.3 ведет себя именно так, и как правильно выстраивать логику работы с данными, чтобы избежать неочевидных конфликтов.
Когда мы устанавливаем БлокировкаДанных в режиме управляемых блокировок, мы должны понимать фундаментальное отличие этого механизма от классических блокировок на уровне СУБД. Платформа 1С оперирует не физическими строками таблицы, а логическим многомерным пространством.
Представим наш регистр сведений как трехмерный куб, где каждое измерение — это ось координат. Когда мы блокируем конкретное значение одного измерения (например, Измерение1 = 1), мы не просто «замораживаем» конкретные строки, существующие в базе данных. Мы блокируем целый «слой» или область в этом многомерном пространстве.
Это делается для выполнения важного требования: защиты от фантомов. Платформа обязана гарантировать, что во время нашей транзакции никто не добавит новую запись, которая попадет под условия нашего отбора. Поскольку система не может знать, какие данные будут внесены в регистр в будущем, она «закрывает» для записи все возможные комбинации, соответствующие заданному значению.
Разберем пример, предложенный автором темы. У нас есть два фрагмента кода:
Фрагмент 1:
НачатьТранзакцию();
Блокировка = Новый БлокировкаДанных;
ЭлБлокировки = Блокировка.Добавить("РегистрСведений.РегистрСведений1");
ЭлБлокировки.УстановитьЗначение("Измерение1", 1);
ЭлБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
// ... работа с данными
ЗафиксироватьТранзакцию();
Фрагмент 2:
НачатьТранзакцию();
Блокировка = Новый БлокировкаДанных;
ЭлБлокировки = Блокировка.Добавить("РегистрСведений.РегистрСведений1");
ЭлБлокировки.УстановитьЗначение("Измерение2", 1);
ЭлБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
// ... работа с данными
ЗафиксироватьТранзакцию();
Конфликт возникает потому, что платформа видит пересечение областей. Первый процесс блокирует все записи, где Измерение1 = 1. Второй процесс блокирует все записи, где Измерение2 = 1. Поскольку теоретически может существовать запись, где оба измерения равны 1 одновременно, система считает эти области пересекающимися и ставит второй процесс в очередь, чтобы предотвратить логическую коллизию.
Чтобы избежать подобных ожиданий, давайте проанализируем следующие правила работы:
БлокировкаДанных как можно больше измерений. Это сужает область «запрета» в многомерном пространстве.1С не требует строгого соблюдения порядка измерений, указание их в порядке, соответствующем логике первичного ключа или наиболее частым запросам, помогает системе быстрее вычислять область блокировки.УстановитьЗначение ограничивает не только текущие записи. Если вы не передали значение для какого-либо измерения, платформа подразумевает, что вы блокируете все возможные значения этого измерения (аналог «любое»).Стоит отметить, что такие «зависания» часто сбивают с толку, так как разработчики привыкли думать категориями SELECT ... WHERE. Однако управляемые блокировки — это надстройка над СУБД, созданная для того, чтобы гарантировать целостность логики 1С независимо от того, какая именно СУБД используется (SQL Server, PostgreSQL и т.д.).
Если вы видите, что транзакции конфликтуют, задайте себе вопрос: «Действительно ли мне нужно блокировать такое широкое пространство данных?». Часто можно пересмотреть логику так, чтобы блокировки накладывались только после того, как ключевые данные уже выбраны и идентифицированы, или использовать более специфичные отборы.
Таким образом, мы выяснили, что ожидание в данном примере — это не ошибка, а штатное поведение механизма УправляемыеБлокировки, направленное на защиту целостности данных регистра при параллельном выполнении транзакций.