Какая блокировка накладывается при чтении через объектную модель и ПолучитьОбъект() в 1С?

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

При подготовке к тестированию «1С:Профессионал по технологическим вопросам» или к экзамену «1С:Эксперт» разработчики часто сталкиваются с вопросами, которые требуют глубокого понимания внутренних механизмов платформы «1С:Предприятие 8». Один из таких классических вопросов — это поведение системы при чтении данных через объектную модель и вызове метода ПолучитьОбъект().

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

Суть вопроса и варианты ответов

Рассмотрим экзаменационный вопрос, вызывающий наибольшее количество споров среди специалистов:

Выберите верное утверждение:

  1. Чтение через объектную модель всегда приводит к наложению управляемой блокировки.
  2. Чтение наборов записей регистров через объектную модель приводит к наложению управляемой блокировки.
  3. Чтение через объектную модель всегда приводит к наложению объектной блокировки.
  4. Получение прикладного объекта через ПолучитьОбъект() всегда происходит с использованием объектной блокировки.
  5. Верны варианты 2 и 4.
  6. Верны все варианты.

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

Управляемые блокировки при чтении регистров (Утверждение 2)

Для начала выясним, почему утверждение под номером 2 является абсолютно верным. Разберем по шагам, что происходит, когда мы считываем данные регистров (сведений, накопления, расчета или бухгалтерии) объектным способом.

Объектный способ работы с регистрами предполагает использование объекта типа РегистрСведенийНаборЗаписей (или аналогичного для других видов регистров). Чтение данных выполняется вызовом метода Прочитать().

При вызове метода Прочитать() на уровне платформы происходит следующее:

Рассмотрим пример кода чтения записей регистра сведений:


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

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

Объектные блокировки при вызове ПолучитьОбъект() (Утверждение 4)

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

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

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

Проанализируем этот процесс на примере параллельной работы двух сеансов:


// Сеанс №1
ОбъектСеанса1 = СсылкаНаТовар.ПолучитьОбъект(); // Считана ВерсияДанных "АAAA"

// В этот момент Сеанс №2 параллельно изменяет этот же товар
// Сеанс №2 успешно записывает изменения, ВерсияДанных в СУБД меняется на "BBBB"

// Сеанс №1 пытается выполнить запись:
ОбъектСеанса1.Наименование = "Новое наименование";
ОбъектСеанса1.Записать(); // Ошибка! Версия в памяти "AAAA" не совпадает с версией в СУБД "BBBB"

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

Почему утверждение 3 («Чтение через объектную модель всегда приводит к наложению объектной блокировки») неверно? Регистры и их наборы записей не поддерживают версионирование данных аналогично объектным сущностям (справочникам и документам). Чтение регистров объектным путем (через наборы записей) не задействует оптимистическую объектную блокировку. Опять же, слово «всегда» делает утверждение ложным.

Различие между объектными и транзакционными блокировками

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

Резюме

Мы детально проанализировали внутреннее поведение платформы «1С:Предприятие 8» при работе с объектным чтением. На основе проведенного анализа делаем однозначные выводы:

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

Таким образом, правильным ответом в тесте «1С:Профессионал» является вариант 5 (верны варианты 2 и 4).

← На главную