При подготовке к тестированию «1С:Профессионал по технологическим вопросам» или к экзамену «1С:Эксперт» разработчики часто сталкиваются с вопросами, которые требуют глубокого понимания внутренних механизмов платформы «1С:Предприятие 8». Один из таких классических вопросов — это поведение системы при чтении данных через объектную модель и вызове метода ПолучитьОбъект().
В этой статье мы подробно разберем, как платформа работает с блокировками данных, почему путаница между управляемыми транзакционными и объектными блокировками приводит к ошибкам, и как на самом деле функционируют механизмы защиты целостности данных при параллельной работе пользователей.
Рассмотрим экзаменационный вопрос, вызывающий наибольшее количество споров среди специалистов:
Выберите верное утверждение:
ПолучитьОбъект() всегда происходит с использованием объектной блокировки.Для того чтобы определить правильный ответ, проанализируем поведение платформы в каждом сценарии работы.
Для начала выясним, почему утверждение под номером 2 является абсолютно верным. Разберем по шагам, что происходит, когда мы считываем данные регистров (сведений, накопления, расчета или бухгалтерии) объектным способом.
Объектный способ работы с регистрами предполагает использование объекта типа РегистрСведенийНаборЗаписей (или аналогичного для других видов регистров). Чтение данных выполняется вызовом метода Прочитать().
При вызове метода Прочитать() на уровне платформы происходит следующее:
TLOCK, подтверждающее установку управляемой транзакционной блокировки.Рассмотрим пример кода чтения записей регистра сведений:
Набор = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
Набор.Отбор.Номенклатура.Установить(ВыбраннаяНоменклатура);
// В этот момент платформа накладывает управляемую разделяемую блокировку на диапазон данных:
Набор.Прочитать();
А почему же тогда утверждение 1 («Чтение через объектную модель всегда приводит к наложению управляемой блокировки») неверно? Дело в том, что при обычном объектном чтении справочников, документов или констант (например, через выборку Выбрать() и последовательный обход методов Следующий()) управляемые блокировки в базу данных по умолчанию не устанавливаются. Так как это происходит не для всех объектов конфигурации, слово «всегда» делает первое утверждение ложным.
Перейдем ко второму важнейшему механизму — объектным блокировкам. Здесь часто возникает недопонимание, поскольку разработчики путают транзакционные блокировки СУБД с логическими механизмами самой платформы 1С.
Когда мы вызываем метод ПолучитьОбъект() у ссылки (например, у справочника или документа), платформа задействует механизм оптимистической объектной блокировки. Выясним причину и механику этого процесса:
Ссылка.ПолучитьОбъект() платформа считывает из базы данных не только бизнес-реквизиты объекта, но и специальное системное поле — ВерсияДанных. Это поле представляет собой уникальную хэш-строку (или метку времени), которая автоматически перезаписывается СУБД при любом физическом изменении записи в базе.СправочникОбъект или ДокументОбъект).Записать() у полученного ранее объекта, платформа выполняет сверку версий. Она считывает актуальную версию записи напрямую из СУБД и сравнивает её с той версией, которая была закэширована в оперативной памяти в момент выполнения ПолучитьОбъект().Проанализируем этот процесс на примере параллельной работы двух сеансов:
// Сеанс №1
ОбъектСеанса1 = СсылкаНаТовар.ПолучитьОбъект(); // Считана ВерсияДанных "АAAA"
// В этот момент Сеанс №2 параллельно изменяет этот же товар
// Сеанс №2 успешно записывает изменения, ВерсияДанных в СУБД меняется на "BBBB"
// Сеанс №1 пытается выполнить запись:
ОбъектСеанса1.Наименование = "Новое наименование";
ОбъектСеанса1.Записать(); // Ошибка! Версия в памяти "AAAA" не совпадает с версией в СУБД "BBBB"
Таким образом, получение прикладного объекта через метод ПолучитьОбъект() всегда инициализирует этот механизм контроля версий данных, что по определению является использованием оптимистической объектной блокировки. Следовательно, утверждение 4 абсолютно верно.
Почему утверждение 3 («Чтение через объектную модель всегда приводит к наложению объектной блокировки») неверно? Регистры и их наборы записей не поддерживают версионирование данных аналогично объектным сущностям (справочникам и документам). Чтение регистров объектным путем (через наборы записей) не задействует оптимистическую объектную блокировку. Опять же, слово «всегда» делает утверждение ложным.
Для успешной работы и сдачи экзаменов крайне важно четко разграничивать эти два понятия. Объединим их различия в структурированный список:
Записать(). Она не удерживает физические блокировки в СУБД во время редактирования объекта.Заблокировать() (или автоматически при открытии формы объекта в режиме редактирования). Она запрещает другим сеансам изменять или блокировать этот объект до тех пор, пока блокировка не будет снята (или пока не закроется форма). Она работает вне рамок транзакций базы данных.Мы детально проанализировали внутреннее поведение платформы «1С:Предприятие 8» при работе с объектным чтением. На основе проведенного анализа делаем однозначные выводы:
Чтение наборов записей регистров через объектный метод Прочитать() всегда сопровождается установкой управляемой транзакционной блокировки. Получение ссылочного прикладного объекта через метод ПолучитьОбъект() всегда задействует встроенный механизм оптимистической объектной блокировки за счет контроля системного поля ВерсияДанных.
Таким образом, правильным ответом в тесте «1С:Профессионал» является вариант 5 (верны варианты 2 и 4).