Почему ЗаблокироватьДанныеДляРедактирования() блокирует данные в разных регистрах сведений и как это исправить

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Суть проблемы: Неожиданная взаимоблокировка разных регистров

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

Проанализируем типичный код, который приводит к такому поведению:


Процедура Тест1НаСервере()
    // Создаем ключ записи для конкретного регистра
    КлючРС = РегистрыСведений.РС1.СоздатьКлючЗаписи(Новый Структура("Док", ВыбДок));
    
    Попытка
        // Пытаемся установить пессимистическую блокировку
        Если БлокировкаФормы Тогда
            ЗаблокироватьДанныеДляРедактирования(КлючРС,, УникальныйИдентификатор);
        Иначе
            ЗаблокироватьДанныеДляРедактирования(КлючРС);
        КонецЕсли; 
    Исключение
        СтрИнфо = СтрШаблон("Данные уже заблокированы! %1", ОписаниеОшибки());
        Сообщить(СтрИнфо);
    КонецПопытки;
КонецПроцедуры

Выясним причину, почему при выполнении этого кода для РС1 в одном сеансе, другой сеанс не может выполнить аналогичный код для РС2. Казалось бы, объекты метаданных разные, и ключи записей должны принадлежать разным пространствам ресурсов.

Анализ механизма блокировок и роль УникальногоИдентификатора

Прежде чем перейти к разбору конкретной ошибки, разберем по шагам, как работает метод ЗаблокироватьДанныеДляРедактирования(). Этот метод реализует так называемую пессимистическую блокировку. В отличие от управляемых блокировок в транзакции, она работает «в памяти» менеджера блокировок кластера 1С и предназначена для интерактивного взаимодействия с пользователем.

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

  1. Вызов без УИД: Блокировка считается краткосрочной. Она удерживается только до момента завершения текущего серверного вызова. Как только управление возвращается на клиента, данные автоматически разблокируются. Это часто используется для предотвращения одновременного запуска фоновых заданий или веб-сервисов из разных потоков в рамках одного вызова.
  2. Вызов с передачей УИД (обычно УИД формы): Блокировка становится сеансовой. Она будет активна до тех пор, пока не будет закрыта форма с этим идентификатором, либо пока не будет вызван метод РазблокироватьДанныеДляРедактирования().

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

Выявление бага платформы: Ошибка 10234370

Проанализируем ситуацию глубже. Почему блокируется РС2, если мы блокируем РС1? Исследования и обращения в техническую поддержку 1С подтвердили, что данное поведение является зарегистрированной ошибкой платформы под номером 10234370.

Причина ошибки кроется во внутреннем алгоритме хеширования ресурсов в менеджере блокировок. Когда в качестве ключа записи регистра сведений выступает структура, содержащая ссылку на объект (документ или справочник), платформа в старых версиях ошибочно идентифицировала ресурс только по значению этой ссылки, игнорируя контекст самого регистра. Таким образом, система «думала», что блокируется не «Запись РС1 с Доком Х», а просто «Документ Х» во всех контекстах ключей записей.

Интересно, что если блокировать саму ссылку на Док1 (объектную сущность), а в другом сеансе блокировать ключ регистра, конфликт мог не возникать, так как пути кода для блокировки объектов и ключей записей в платформе различаются.

Как решить проблему и обойти ограничение

Рассмотрим способы устранения данной проблемы. Поскольку это внутренняя ошибка платформы, основным решением является обновление программного обеспечения.

1. Обновление версии платформы

Данная ошибка была официально исправлена в следующих выпусках (и более поздних):

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

2. Проверка корректности создания ключа записи

При работе с регистрами сведений важно убедиться, что КлючЗаписи сформирован правильно. Метод СоздатьКлючЗаписи() должен содержать все измерения, входящие в уникальность записи. Рассмотрим пример правильного формирования ключа:


// Предположим, у регистра есть измерения "Объект" и "Период" (если он периодический)
СтруктураКлюча = Новый Структура;
СтруктураКлюча.Вставить("Объект", СсылкаНаДокумент);
// Если регистр периодический, период также должен входить в ключ для точной идентификации
// СтруктураКлюча.Вставить("Период", ДатаЗаписи); 

Ключ = РегистрыСведений.МойРегистр.СоздатьКлючЗаписи(СтруктураКлюча);
ЗаблокироватьДанныеДляРедактирования(Ключ,, ЭтаФорма.УникальныйИдентификатор);

3. Использование управляемых блокировок как альтернативы

Если цель блокировки — не запретить пользователю открывать форму, а предотвратить одновременное изменение данных в коде (например, в транзакции), то следует использовать объект БлокировкаДанных. Разберем разницу:

Резюме

Подведем итог. Если вы столкнулись с тем, что метод ЗаблокироватьДанныеДляРедактирования() ведет себя агрессивно и блокирует лишние объекты, в первую очередь проверьте версию вашей платформы. Скорее всего, вы столкнулись с багом 10234370. В качестве временного решения (до обновления) можно попробовать изменить логику взаимодействия, чтобы избежать блокировок по ключу записи, либо перейти на использование управляемых блокировок в тех местах, где это допустимо по бизнес-логике.

Помните, что пессимистическая блокировка — это механизм визуального оповещения пользователя о том, что «кто-то другой уже открыл этот объект на редактирование». Для обеспечения строгой целостности данных всегда используйте механизмы управляемых блокировок внутри транзакций.

← На главную