В практике разработки на платформе 1С:Предприятие 8.3 иногда встречаются ситуации, которые на первый взгляд кажутся мистическими. Представьте: вы меняете данные в документе, записываете его, проводите, но в другом сеансе (например, у кассира в магазине) запрос упорно продолжает выдавать старые значения. Причем проблема носит эпизодический характер и «лечится» только перезапуском программы. Мы разберем причины такого поведения, проанализируем механизмы кэширования 1С и выясним, почему архитектурное решение «один документ для всех цен» является тупиковым.
Рассмотрим исходную схему, которая привела к возникновению проблемы. Был создан один документ КрасныеЦены, в табличной части которого хранился список номенклатуры с минимальной наценкой. При продаже в РМК выполнялся простейший запрос к этой табличной части:
ВЫБРАТЬ
докТовары.Номенклатура
ИЗ
Документ.КрасныеЦены.Товары КАК докТовары
ГДЕ
докТовары.Ссылка.Проведен
И докТовары.Номенклатура В (&массивНоменклатуры)
Основная ошибка здесь заключается в попытке использовать объект метаданных «Документ» в качестве хранилища оперативно меняющихся настроек или констант. Документы в 1С предназначены для регистрации событий во времени, а не для хранения актуальных состояний. Когда мы постоянно перезаписываем один и тот же объект с огромной табличной частью, мы заставляем платформу и СУБД работать в нештатном для них режиме.
Проанализируем, что происходит «под капотом» платформы. В 1С существует несколько уровней кэширования, и именно их несогласованность в редких случаях приводит к описанным эффектам.
Документ.КрасныеЦены может не дойти до конкретного рабочего процесса.ПриПолученииДанныхНаСервере формы списка, стоит учитывать, что у динамического списка есть свой внутренний механизм выборки данных. Он не всегда инициирует полный перезапрос к СУБД, если визуально состав строк не изменился.Выясним причину на уровне базы данных. В современных конфигурациях 1С на MS SQL Server часто используется режим Read Committed Snapshot. Он позволяет читать данные, не блокируясь пишущими транзакциями. Рассмотрим сценарий:
Пока один менеджер в офисе записывает (проводит) документ КрасныеЦены, транзакция в SQL еще не завершена. В этот момент кассир в магазине делает запрос. SQL Server, чтобы не заставлять кассира ждать, отдает ему снимок данных (snapshot), актуальный на момент начала транзакции менеджера. Если транзакция записи документа длительная (из-за большой табличной части), все запросы извне будут получать старую версию данных до тех пор, пока транзакция не зафиксируется (Commit). Однако, из-за особенностей работы сервера приложений 1С, сеанс может «залипнуть» на этом снимке чуть дольше, чем длится сама транзакция.
Проанализируем, почему замена документа на Регистр Сведений мгновенно исправляет ситуацию. Работа с регистрами в 1С оптимизирована для частых чтений и точечных записей:
Номенклатура) выполняется значительно быстрее, чем сканирование табличной части документа.Разберем по шагам, как правильно реализовать подобную проверку. Вместо запроса к документу создадим периодический или непериодический Регистр Сведений КрасныеЦены с измерением Номенклатура.
Запрос в модуле РМК теперь будет выглядеть так:
ВЫБРАТЬ
КрасныеЦены.Номенклатура КАК Номенклатура
ИЗ
РегистрСведений.КрасныеЦены КАК КрасныеЦены
ГДЕ
КрасныеЦены.Номенклатура В (&МассивЧека)
Если нам необходимо сохранить возможность редактирования списка через документ (для истории или согласования), мы можем оставить документ, но при его проведении записывать данные в регистр сведений. Для этого используем процедуру ОбработкаПроведения:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Очищаем старые записи регистра по этому документу (если регистр подчинен)
// Или просто обновляем актуальное состояние
НаборЗаписей = РегистрыСведений.КрасныеЦены.СоздатьНаборЗаписей();
Для Каждого Стр Из Товары Цикл
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Номенклатура = Стр.Номенклатура;
// Дополнительные реквизиты, если нужно
КонецЦикла;
НаборЗаписей.Записать();
КонецПроцедуры
Если по каким-то причинам вы вынуждены продолжать работу с запросами к документам или справочникам и столкнулись с кэшированием, рассмотрим «грязные», но рабочие способы форсирования обновления:
Повторное использование возвращаемых значений в значение Не использовать, но, как мы видели в обсуждении, это не всегда помогает против системного кэша записей.Мы выяснили, что «непонятные глюки» с обновлением данных в 1С чаще всего имеют под собой вполне логичное техническое объяснение: механизмы оптимизации платформы (кэширование) конфликтуют с неоптимальной архитектурой данных. Главный вывод: для любых проверок, настроек и оперативных списков всегда используйте Регистры Сведений. Это не только снимет вопросы с кэшированием, но и значительно повысит производительность системы за счет правильного использования индексов СУБД.