Как программно проверить, открыт или заблокирован ли документ другим пользователем в 1С?

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

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

Ограничения платформы и частые заблуждения

Проанализируем сначала, как 1С работает с открытыми формами документов. Простое открытие формы документа (особенно в режиме просмотра) не накладывает пессимистическую блокировку в базе данных. Платформа 1С не хранит встроенного реестра документов, просто «открытых на экране» у пользователей.

Часто разработчики пытаются использовать метод Заблокирован() у объекта документа, ожидания, что он вернет Истина, если документ редактируется кем-то другим. Однако это не так.

Важно: Метод Заблокирован() проверяет только то, заблокирован ли объект текущим экземпляром объекта встроенного языка в текущем сеансе. Он всегда возвращает Ложь для блокировок, установленных другими пользователями или другими переменными.

Способ 1. Проверка пессимистической блокировки через «Попытка ... Исключение»

Единственный штатный способ узнать, редактируется ли документ другим пользователем в данный момент — попытаться явно установить на него пессимистическую блокировку и перехватить исключение.

Если другой пользователь уже начал редактировать форму документа, платформа накладывает на этот документ пессимистическую блокировку. Чтобы проверить наличие блокировки на сервере, выполним следующий код:


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

Если документ заблокирован другим сеансом, метод Заблокировать() вызовет ошибку, и управление перейдет в блок Исключение.

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


&НаКлиенте
Функция ПроверитьБлокировкуНаКлиенте(СсылкаНаДокумент, УникальныйИдентификаторФормы)
    
    Заблокирован = Ложь;
    
    Попытка
        ЗаблокироватьДанныеДляРедактирования(СсылкаНаДокумент, , УникальныйИдентификаторФормы);
        // Если блокировка успешно установлена и она нам не нужна, сразу снимаем её
        РазблокироватьДанныеДляРедактирования(СсылкаНаДокумент, УникальныйИдентификаторФормы);
    Исключение
        Заблокирован = Истина;
    КонецПопытки;
    
    Возврат Заблокирован;
    
КонецФункции

Способ 2. Транзакционная проверка списка документов (`БлокировкаДанных`)

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

Для этого оптимально использовать объект БлокировкаДанных внутри транзакции. Разберем пример реализации:


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

Как узнать, кто именно заблокировал документ?

При перехвате исключения в блоке Исключение можно проанализировать текст ошибки с помощью функции ОписаниеОшибки() или ИнформацияОбОшибке(). В клиент-серверном режиме платформа формирует системное сообщение с указанием имени компьютера, имени пользователя и номера сеанса, заблокировавшего объект.

Для получения подробных данных о пользователе можно использовать функцию встроенного языка ПолучитьСеансыИнформационнойБазы(), сопоставив номер сеанса из текста ошибки с активными сеансами базы данных.

Резюме

  1. Метод Заблокирован() не проверяет блокировку объекта в базе данных другими пользователями.
  2. Для проверки блокировки конкретного документа используйте конструкции Попытка ... Исключение с вызовом Заблокировать() или ЗаблокироватьДанныеДляРедактирования().
  3. Для групповой проверки и записи массива документов применяйте БлокировкаДанных в режиме Исключительный внутри транзакции.
← На главную