Почему запрос к документу 1С возвращает старые данные и как бороться с глюками кэширования

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

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

Разбор ситуации: Архитектурный антипаттерн

Рассмотрим исходную схему, которая привела к возникновению проблемы. Был создан один документ КрасныеЦены, в табличной части которого хранился список номенклатуры с минимальной наценкой. При продаже в РМК выполнялся простейший запрос к этой табличной части:


ВЫБРАТЬ
    докТовары.Номенклатура
ИЗ
    Документ.КрасныеЦены.Товары КАК докТовары
ГДЕ
    докТовары.Ссылка.Проведен
    И докТовары.Номенклатура В (&массивНоменклатуры)

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

Механизмы кэширования: Почему данные не обновляются

Проанализируем, что происходит «под капотом» платформы. В 1С существует несколько уровней кэширования, и именно их несогласованность в редких случаях приводит к описанным эффектам.

  1. System Record Cache (Системный кэш записей): Сервер приложений 1С кэширует данные, прочитанные из СУБД. Когда один пользователь меняет документ, система должна отправить уведомление об изменении (инвалидации) кэша всем остальным сеансам. В условиях нестабильной сети между удаленными магазинами и центральным сервером или при высокой нагрузке сигнал об изменении конкретной записи Документ.КрасныеЦены может не дойти до конкретного рабочего процесса.
  2. Объектный кэш сеанса: Если в сеансе магазина ранее уже происходило обращение к этому документу (например, при открытии формы или программном чтении), данные объекта оседают в памяти текущего сеанса. Платформа старается минимизировать обращения к SQL-серверу и может вернуть данные из локальной памяти.
  3. Особенности Динамических списков: Если проверка выполняется в событии ПриПолученииДанныхНаСервере формы списка, стоит учитывать, что у динамического списка есть свой внутренний механизм выборки данных. Он не всегда инициирует полный перезапрос к СУБД, если визуально состав строк не изменился.

Влияние режима Read Committed Snapshot (RCSI)

Выясним причину на уровне базы данных. В современных конфигурациях 1С на MS SQL Server часто используется режим Read Committed Snapshot. Он позволяет читать данные, не блокируясь пишущими транзакциями. Рассмотрим сценарий:

Пока один менеджер в офисе записывает (проводит) документ КрасныеЦены, транзакция в SQL еще не завершена. В этот момент кассир в магазине делает запрос. SQL Server, чтобы не заставлять кассира ждать, отдает ему снимок данных (snapshot), актуальный на момент начала транзакции менеджера. Если транзакция записи документа длительная (из-за большой табличной части), все запросы извне будут получать старую версию данных до тех пор, пока транзакция не зафиксируется (Commit). Однако, из-за особенностей работы сервера приложений 1С, сеанс может «залипнуть» на этом снимке чуть дольше, чем длится сама транзакция.

Почему переход на Регистр Сведений решает проблему

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

Реализация правильной архитектуры

Разберем по шагам, как правильно реализовать подобную проверку. Вместо запроса к документу создадим периодический или непериодический Регистр Сведений КрасныеЦены с измерением Номенклатура.

Запрос в модуле РМК теперь будет выглядеть так:


ВЫБРАТЬ
    КрасныеЦены.Номенклатура КАК Номенклатура
ИЗ
    РегистрСведений.КрасныеЦены КАК КрасныеЦены
ГДЕ
    КрасныеЦены.Номенклатура В (&МассивЧека)

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


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

Как гарантированно обойти кэш (если регистр невозможен)

Если по каким-то причинам вы вынуждены продолжать работу с запросами к документам или справочникам и столкнулись с кэшированием, рассмотрим «грязные», но рабочие способы форсирования обновления:

  1. Использование параметров: Добавление в запрос фиктивного параметра, который всегда меняется (например, текущая дата с секундами), иногда заставляет платформу выполнить запрос заново, минуя некоторые уровни кэша запросов.
  2. Разделение сеансов: В критически важных местах для получения актуальных данных можно использовать вызов серверного метода с установленным признаком Повторное использование возвращаемых значений в значение Не использовать, но, как мы видели в обсуждении, это не всегда помогает против системного кэша записей.
  3. Метод ОбновитьОтображение(): В управляемых формах этот метод заставляет интерфейс перечитать данные, но он не гарантирует обновление результата произвольного запроса в коде.

Резюме

Мы выяснили, что «непонятные глюки» с обновлением данных в 1С чаще всего имеют под собой вполне логичное техническое объяснение: механизмы оптимизации платформы (кэширование) конфликтуют с неоптимальной архитектурой данных. Главный вывод: для любых проверок, настроек и оперативных списков всегда используйте Регистры Сведений. Это не только снимет вопросы с кэшированием, но и значительно повысит производительность системы за счет правильного использования индексов СУБД.

← На главную