Почему пессимистическая блокировка не запрещает программную запись объекта и в чем ее отличие от транзакционной?

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

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

Анализ проблемы: ожидания против реальности

Рассмотрим стандартную ситуацию. Пользователь открыл форму документа и начал вносить изменения. В этот момент система (расширение формы) автоматически устанавливает пессимистическую блокировку. Разработчик ожидает, что теперь любая попытка изменить этот объект — будь то через другую форму или программно через ПолучитьОбъект().Записать() — должна привести к ошибке "Объект заблокирован".

Однако на практике программный код во втором сеансе беспрепятственно записывает данные. Проанализируем причину этого поведения. Основная проблема заключается в том, что пессимистическая блокировка — это механизм прикладного уровня. Она существует в памяти менеджера блокировок кластера 1С, а не на уровне СУБД. Более того, встроенный метод Записать() по умолчанию не проверяет наличие объектных блокировок. Он проверяет только оптимистическую блокировку (соответствие версий объекта).

Разбор механизма пессимистической блокировки

Пессимистическая блокировка объектов базы данных предназначена для того, чтобы предотвратить редактирование одних и тех же данных разными пользователями через интерфейс. Рассмотрим ключевые особенности этого механизма:

  1. Локализация: Блокировка живет в памяти рабочего процесса 1С. СУБД (SQL Server, PostgreSQL) ничего не знает об этой блокировке.
  2. Добровольность: Метод Записать() не обязан проверять пессимистическую блокировку. Эту проверку выполняют только те механизмы, которые сами пытаются установить блокировку перед началом работы.
  3. Триггер срабатывания: В управляемых формах блокировка устанавливается не в момент открытия, а в момент начала модификации данных в форме (когда свойство Модифицированность становится Истина).

Таким образом, если программный код просто получает объект и записывает его, он игнорирует "флажок" в памяти кластера, который поставила форма первого пользователя.

Решение 1: Программная установка пессимистической блокировки

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

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


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

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

Обратите внимание: если во втором сеансе не вызвать Заблокировать(), то метод Записать() просто перезатрет данные, проигнорировав открытую форму в первом сеансе.

Решение 2: Использование метода ЗаблокироватьДанныеДляРедактирования

В современной платформе 1С v8.3 для управляемых форм рекомендуется использовать метод ЗаблокироватьДанныеДляРедактирования(). Этот метод работает с идентификаторами данных (ссылками) и более тесно интегрирован с механизмом форм.

Рассмотрим пример использования этого метода:


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

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

Транзакционные блокировки: уровень СУБД

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

Основные отличия:

  1. Длительность: Пессимистическая блокировка длится долго (пока открыта форма). Транзакционная блокировка длится доли секунды (пока данные физически пишутся на диск).
  2. Цель: Пессимистическая блокировка защищает от логических ошибок (два человека правят одно поле). Транзакционная блокировка защищает от физического повреждения данных и обеспечивает целостность базы (ACID).
  3. Влияние: Транзакционная блокировка всегда "видит" другие транзакционные блокировки и заставляет сеансы ждать своей очереди. Пессимистическая блокировка видна только тем, кто о ней "спрашивает" через методы Заблокировать().

Оптимистическая блокировка: последняя линия обороны

Даже если мы не используем метод Заблокировать(), 1С защищает данные с помощью оптимистической блокировки. Она основана на версии объекта (поле DataVersion в СУБД).

Проанализируем сценарий:

  1. Пользователь А открыл форму (версия объекта 1).
  2. Пользователь Б программно изменил объект (версия в базе стала 2).
  3. Пользователь А нажимает "Записать" в форме.

В этот момент система сравнивает версию, которая была при открытии (1), с текущей версией в базе (2). Поскольку они различаются, пользователь А получит ошибку: "Данные были изменены или удалены другим пользователем". Это и есть работа оптимистической блокировки. Она не запрещает запись в процессе, но проверяет результат "по факту" перед окончательным коммитом.

Итоги и рекомендации

Для обеспечения надежной работы системы и предотвращения потери данных придерживайтесь следующих правил:

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

← На главную