Как работает и устанавливается оптимистическая блокировка в 1С

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

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

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

Давайте сразу внесем ясность: оптимистическая блокировка не устанавливается программно в том смысле, в котором мы привыкли работать с объектами. Это не действие, которое мы инициируем кодом, а стратегия поведения платформы. Само название «блокировка» здесь несколько условно. Правильнее называть это оптимистическим контролем версий.

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

Механизм ВерсияДанных: «скрытый» страж целостности

Рассмотрим, на чем базируется этот механизм. У каждого ссылочного объекта (справочники, документы и т.д.) в 1С существует системный реквизит ВерсияДанных. Это скрытое поле, которое обновляется платформой автоматически при каждой успешной записи объекта в базу данных.

Проанализируем техническую реализацию:

  1. На уровне СУБД (например, MS SQL Server) этот реквизит соответствует типу rowversion. Это постоянно инкрементируемое число, уникальное в рамках всей базы.
  2. При считывании объекта (например, при открытии управляемой формы) платформа запоминает текущее значение ВерсияДанных.
  3. Когда пользователь нажимает кнопку «Записать», платформа отправляет измененные данные на сервер вместе с той версией, которую она считала ранее.
  4. В момент записи выполняется SQL-запрос, который содержит условие соответствия версии. Если в базе версия уже изменилась (кто-то другой успел записать объект), условие WHERE не сработает, и 1С выдаст знаменитую ошибку: «Данные были изменены или удалены другим пользователем».

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

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

Пессимистическая блокировка:

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

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

Хотя метода «установить блокировку» не существует, начиная с версии 8.3.15, у программистов появилось гораздо больше инструментов для взаимодействия с этим механизмом. Рассмотрим основные сценарии.

1. Получение версии данных через запрос

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура.ВерсияДанных КАК ТекущаяВерсия
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |   Номенклатура.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект);
Результат = Запрос.Выполнить().Выбрать();

Если Результат.Следующий() Тогда
    Если Результат.ТекущаяВерсия <> ВерсияВПамяти Тогда
        Сообщить("Внимание! Объект уже был изменен в базе.");
    КонецЕсли;
КонецЕсли;

2. Ручная проверка перед тяжелыми операциями

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


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

// Перед записью проверяем версию еще раз (программное перечитывание)
Если ОбъектСпр.ВерсияДанных <> ПолучитьАктуальнуюВерсиюИзБазы(СсылкаНаОбъект) Тогда
    ВызватьИсключение "Данные устарели, расчеты неактуальны!";
КонецЕсли;

ОбъектСпр.Записать();

3. Использование в независимых регистрах сведений

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


Набор = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
Набор.Отбор.Номенклатура.Установить(ВыбраннаяНоменклатура);

// Указываем версию, которую мы прочитали ранее. 
// Если в базе версия уже другая — Записать() выдаст исключение.
Набор.УстановитьВерсиюДанных(ПрочитаннаяРанееВерсия); 

Попытка
    Набор.Записать();
Исключение
    Сообщить("Ошибка: данные регистра были изменены другим процессом.");
КонецПопытки;

Оптимистическая блокировка и транзакции

Важно не путать объектную оптимистическую блокировку с блокировкой данных в транзакции (объект БлокировкаДанных).

Оптимистическая блокировка защищает от ситуации, когда два пользователя редактируют один и тот же справочник в течение 10 минут и один затирает изменения другого.

Транзакционная блокировка (пессимистическая по своей сути) защищает данные в течение миллисекунд или секунд, пока выполняется код на сервере (например, ОбработкаПроведения), чтобы в этот момент никто не смог изменить остатки, которые мы сейчас проверяем.

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

Резюме для разработчика

Выясним главные правила работы с этим механизмом:

  1. Не ищите метод установки: Оптимистическая блокировка работает «из коробки» для всех объектов.
  2. Помните про ВерсияДанных: Это поле — ваш главный инструмент контроля. Оно меняется при каждом вызове Записать(), если данные реально изменились.
  3. Обрабатывайте исключения: Всегда заключайте запись объектов в блоки Попытка...Исключение, так как вероятность конфликта оптимистической блокировки существует всегда, особенно в высоконагруженных системах.
  4. Используйте OData и REST: Если вы пишете интеграцию, помните, что 1С поддерживает заголовок If-Match, который использует ВерсияДанных как ETag для реализации оптимистического контроля в веб-сервисах.

Таким образом, оптимистическая блокировка — это невидимый, но надежный фундамент 1С, который позволяет системе работать быстро без лишних ожиданий на уровне СУБД, обеспечивая при этом сохранность данных при параллельной работе пользователей.

← На главную