Как правильно устанавливать блокировки при одновременном изменении документа пользователем и обработкой

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

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

Разберем виды блокировок: Пессимистическая vs Оптимистическая

Для начала проанализируем, чем отличаются основные подходы к блокированию данных. В 1С существует два уровня контроля доступа к объекту в пользовательском режиме.

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

Пессимистическая блокировка, напротив, захватывает объект сразу. Как только Пользователь 1 начинает редактировать данные в форме (или вызывается метод ЗаблокироватьДанныеФормыДляРедактирования), другие пользователи не смогут захватить этот объект для изменения. Попытка программно заблокировать такой объект в обработке приведет к исключению.

Программная реализация в обработке (Пользователь 2)

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

Посмотрим на пример правильной реализации логики в обработке:


// Получаем объект документа по ссылке, найденной запросом
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();

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

В данном примере метод Заблокировать() крайне важен. Если Пользователь 1 уже открыл форму документа и начал вносить изменения, этот метод мгновенно выдаст ошибку, и обработка Пользователя 2 не «затрет» изменения Пользователя 1. Мы корректно обрабатываем это в блоке Исключение.

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

Для того чтобы уменьшить время блокировки и повысить параллельность работы, в современных конфигурациях на платформе 8.3 используются управляемые блокировки. Они работают внутри транзакции и позволяют защитить данные на уровне СУБД.

Рассмотрим ситуацию: обработка Пользователя 2 сначала ищет документы запросом по определенному условию, а затем меняет их. Чтобы между поиском и изменением данные не изменились кем-то третьим, мы можем использовать объект БлокировкаДанных.

Разберем по шагам, как это реализовать:

  1. Создаем объект БлокировкаДанных.
  2. Описываем элемент блокировки (указываем пространство имен, например, Документ.РеализацияТоваровУслуг).
  3. Устанавливаем режим (Исключительный или Разделяемый).
  4. Устанавливаем значения фильтра (по каким конкретно документам мы ставим блок).
  5. Вызываем метод Заблокировать() перед началом транзакции записи.

Пример кода для управляемой блокировки внутри транзакции:


Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Документ.РеализацияТоваровУслуг");
ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНаДокумент);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;

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

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

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

Подведем итоги

Правильная стратегия совместной работы пользователя и программного кода в 1С строится на комбинации трех уровней защиты:

1. Пессимистическая блокировка в форме: защищает Пользователя 1 от того, чтобы кто-то другой начал редактировать документ одновременно с ним в интерфейсе.

2. Метод Объект.Заблокировать() в коде: обязателен для использования в обработках и фоновых заданиях. Это «вежливый» способ спросить у системы: «Не занят ли сейчас этот документ кем-то другим в форме?».

3. Управляемые блокировки (DataLock): необходимы для защиты данных в момент самой записи внутри транзакции, чтобы обеспечить целостность базы данных на уровне СУБД.

Соблюдение этих правил позволит избежать конфликтов записи и сделает работу системы стабильной даже при высокой интенсивности изменений одних и тех же объектов.

← На главную