В процессе многопользовательской работы в системе 1С часто возникает ситуация, когда два или более сотрудников одновременно открывают один и тот же документ для внесения правок. По умолчанию платформа 1С использует так называемую оптимистическую блокировку. Это означает, что система позволяет всем пользователям открывать и изменять данные, но при попытке записи документа вторым пользователем выдается ошибка: "Данные были изменены или удалены другим пользователем".
Для многих бизнес-процессов, где заполнение документа занимает длительное время, такая ситуация неприемлема, так как работа одного из сотрудников будет потеряна. В данной статье мы разберем по шагам, как реализовать пессимистическую блокировку — механизм, при котором первый открывший документ пользователь «захватывает» его, а все последующие могут просматривать его только в режиме чтения.
Для реализации задачи в управляемом приложении мы воспользуемся методом ЗаблокироватьДанныеДляРедактирования(). Этот метод позволяет заблокировать объект базы данных для конкретной формы. Рассмотрим подробнее, как это реализовать в модуле формы документа.
Основную логику необходимо прописать в серверной процедуре ПриСозданииНаСервере. Мы попытаемся установить блокировку, и если она не удастся (объект уже занят), переведем форму в режим «Только просмотр».
Проанализируем пример кода (для быстрой генерации подобных каркасов удобно использовать консоль кода с ИИ-помощником):
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем, что это не новый документ, так как новый блокировать нет смысла
Если Не Объект.Ссылка.Пустая() Тогда
Попытка
// Пытаемся заблокировать данные для текущей формы
ЗаблокироватьДанныеДляРедактирования(Объект.Ссылка, , ЭтаФорма.УникальныйИдентификатор);
Исключение
// Если возникло исключение, значит объект уже заблокирован другим сеансом
ЭтаФорма.ТолькоПросмотр = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Внимание! Документ редактируется другим пользователем. Форма открыта только для просмотра.");
КонецПопытки;
КонецЕсли;
КонецПроцедуры
В данном коде УникальныйИдентификатор формы связывает блокировку именно с этим окном. Когда пользователь закроет форму, платформа автоматически попытается снять блокировку.
Простого сообщения о том, что документ занят, часто недостаточно. Пользователю важно знать, кто именно открыл документ, чтобы связаться с коллегой. Мы можем извлечь информацию о номере сеанса из текста ошибки и сопоставить её со списком активных пользователей.
Рассмотрим более продвинутый вариант обработки исключения (хотя в некоторых случаях администратору требуется обратное — открыть доступность элементов формы принудительно):
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Не Объект.Ссылка.Пустая() Тогда
Попытка
ЗаблокироватьДанныеДляРедактирования(Объект.Ссылка, , ЭтаФорма.УникальныйИдентификатор);
Исключение
ЭтаФорма.ТолькоПросмотр = Истина;
ТекстОшибки = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
// Парсим строку ошибки для получения номера сеанса
ПозицияСеанса = Найти(ТекстОшибки, "сеанс:");
Если ПозицияСеанса > 0 Тогда
ОбрезаннаяОшибка = Сред(ТекстОшибки, ПозицияСеанса + 6);
НомерСеансаСтрокой = Сокращенно(Сред(ОбрезаннаяОшибка, 1, Найти(ОбрезаннаяОшибка, ",") - 1));
НомерСеанса = Число(НомерСеансаСтрокой);
// Ищем имя пользователя по номеру сеанса
АктивныеСеансы = ПолучитьСеансыИнформационнойБазы();
ИмяПользователя = "Не определен";
Для Каждого Сеанс Из АктивныеСеансы Цикл
Если Сеанс.НомерСеанса = НомерСеанса Тогда
ИмяПользователя = Сеанс.Пользователь.ПолноеИмя;
Прервать;
КонецЕсли;
КонецЦикла;
Сообщить("Документ заблокирован пользователем: " + ИмяПользователя + " (Сеанс №" + НомерСеансаСтрокой + ")");
Иначе
Сообщить("Документ редактируется другим пользователем.");
КонецЕсли;
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Обратите внимание: парсинг текста ошибки по слову "сеанс" может зависеть от версии платформы и языка интерфейса. В промышленных решениях рекомендуется использовать более надежные способы из Библиотеки стандартных подсистем (БСП).
Существует важный нюанс: при закрытии формы блокировка может сниматься не мгновенно. Если пользователь быстро закрыл и снова открыл документ, он может столкнуться с собственной блокировкой. Чтобы избежать этого, рекомендуется явно освобождать данные при закрытии формы.
Выясним, как это сделать правильно. Поскольку метод разблокировки доступен только на сервере, нам потребуется клиент-серверный вызов (а для ускорения проверки таких сценариев пригодится помощник отладки):
&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
РазблокироватьНаСервере();
КонецПроцедуры
&НаСервере
Процедура РазблокироватьНаСервере()
// Снимаем блокировку, установленную ранее для этой формы
РазблокироватьДанныеДляРедактирования(Объект.Ссылка, ЭтаФорма.УникальныйИдентификатор);
КонецПроцедуры
Использование УникальныйИдентификатор гарантирует, что мы снимем именно ту блокировку, которую установили при открытии данного окна.
Иногда системные блокировки ведут себя слишком жестко (например, если сеанс "подвис", объект останется заблокированным до перезагрузки сервера). Альтернативный вариант — создание собственного механизма на базе Регистра Сведений.
Алгоритм решения выглядит следующим образом:
ЗанятыеОбъекты с измерениями Объект (ЛюбаяСсылка) и ресурсами Пользователь, ДатаЗахвата.ТолькоПросмотр.Преимущества данного метода:
Если ваша конфигурация построена на базе БСП (например, УТ 11, ERP 2, БП 3.0), то писать код вручную не обязательно. В составе библиотеки есть подсистема "Запрет редактирования объектов".
Проанализируем возможности БСП:
Для подключения достаточно включить соответствующую функциональную опцию в настройках программы или добавить объект в состав определяемых типов подсистемы блокировок.
Посмотрим на ситуацию со стороны системного администрирования. Массовое использование пессимистических блокировок во всех документах базы может привести к следующим последствиям:
Совет: Используйте принудительную блокировку только для критически важных документов с длинным циклом редактирования. Для простых справочников и мелких документов штатной оптимистической блокировки 1С вполне достаточно.
Подводя итог, мы рассмотрели три способа решения проблемы: программную блокировку средствами платформы, идентификацию пользователя-держателя блокировки и создание кастомного механизма через регистры. Выбор конкретного метода зависит от архитектуры вашей конфигурации и требований бизнеса к отказоустойчивости.