1с повторное использование. Общие модули. Параметр "Повторное использование"

Часто нам приходится по ходу исполнения программы получать значения, которые хранятся в базе данных и не меняются годами. Яркий пример - значения констант. Отчасти, можно причислить сюда же поиск элемента справочника или узла плана обмена по коду, получение значений реквизитов объектов по ссылке.

Не думая, "на лету" такие задачи решаются конструкциями вида:

Если ДатаДокумента > Константы.ДатаНачалаПримененияПостановления1137.Получить() Тогда

В результате, каждый раз когда выполняется этот код - происходит "дерганье" базы данных.

Программисты более щепетильно относящиеся к своему коду, выполняют один запрос к базе данных, кэшируя все данные которые им понадобятся, однако такой подход не всегда приводит к желаемой разгрузке БД:

  1. Цикл выполнения кода может быть неявным (например, групповое перепроведение документов)
  2. Получить строгий набор данных (не больше и не меньше), которые потребуются позже, иногда затруднительно или вовсе невозможно.
  3. Кэшированные значения требуется использовать в разных вызовах/формах

Модуль с повторным использованием возвращаемых значений

Для решения описанных проблем в платформе есть модули с повторным использованием возвращаемых значений. Фактически, это обычный общий модуль (клиентский или серверный), в котором Повторное использование возвращаемых значений установлено в "На время вызова" или "На время сеанса". В самом модуле процедуры и функции описываются как обычно.

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

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

Узел1 = НашМодуль.ПолучитьУзелОбменаСБухгалтерией("0001"); Узел2 = НашМодуль.ПолучитьУзелОбменаСБухгалтерией("0002");

Оба вызова действительно приведут к выполнению соответствующей процедуры и вернут разные ссылки, а при последующих попытках получить узел с кодом 0001 или 0002 - будут возвращаться соответствующие узлы без вызова процедуры и, как следствие, базы данных.

Значения кэшируются отдельно для каждого сеанса на клиенте или сервере (в зависимости от того клиентский или серверный модуль). Т.е. если есть особенности настройки прав доступа или другой зависимости полученного значения от текущего пользователя - все отработает корректно.

Чего делать нельзя

Есть одно ограничение. В качестве параметров функций можно указывать только простые типы. Неопределено, Null, Булево, Дата, Строка, Число, Ссылка. Никаких структур, таблиц значений, объектов и т.п. Если вы попытаетесь передать в качестве параметра, например, структуру - все отработает, но о повторном использовании полученного значения можете забыть.

Возвращаемое значение при этом может быть любого типа.

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

Баг или фича от 1С

Интересное свойство есть у повторно используемых значений. Баг это или фича непонятно, но знать о нем не помешет. Если выполнить код следующего характера:

ЗначениеСтруктура1 = НашМодуль.ПолучитьСтруктуруЗначенийРеквизитов(СсылкаНаОбъект); ЗначениеСтруктура1.Наименование = "Новое наименование"; ЗначениеСтруктура2 = НашМодуль.ПолучитьСтруктуруЗначенийРеквизитов(СсылкаНаОбъект);

То в ЗначениеСтруктура2.Наименование будет лежать именно "Новое наименование". В принципе, это можно использовать для обновления значений, реально измененных в БД, но когда прикроют и прикроют ли лавочку - непонятно. При разработке типовых решений так делать запрещено.

Что делать при изменении закэшированных данных

Есть всего лишь один "легитимный" метод обработать ситуацию с изменением закэшированного значения в базе данных. Это метод ОбновитьПовторноИспользуемыеЗначения(). Будут сброшены значения всех функций по всем параметрам всех модулей. Обновить по конкретным значениям параметров / функциям / модулям нельзя.

Соответственно, из-за такого волюнтаристского подхода, пользоваться этой функцией необходимо крайне осмотрительно: вся система после его использования какое-то время будет работать существенно медленнее.

Посягаем на святое: пишем запрос в цикле

Кроме очевидных вариантов использования функций с повторным использованием возвращаемых значений, есть немало интересных, универсальных, нестандартных подходов, среди которых:

  • Написание универсальных процедур, возвращающих реквизиты произвольных ссылок (есть в БСП)
  • Написание процедур, возвращающих значения констант по имени константы (есть в большинстве типовых)
  • Возврат "чуть большего" объема данных, чем необходимо ради уменьшения количества вызовов (напр. если требуется получить курсы сразу нескольких валют, имеет смысл вызывать функцию по дате без отбора валюты, получить курсы всех валют и далее "разбираться на месте" какая из валют в настоящий момент нужна)
  • Написание процедуры, выполняющей запрос с кэшированием результата (входящими параметрами при этом будут текст запроса и пара-тройка имен и значений параметров)

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

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

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

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

Проблемы при работе с 1С

Зачастую, работая с программой 1С, требуется получение значений, хранящихся в базе данных, они не меняются годами. Примером может быть значение констант. К этой группе значений можно условно причислить поиск одного из элементов справочника или поиск узла плана обмена, используя код, а также необходимость получить значение реквизитов объектов.

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

Если ДатаДокумента > Константы.ДатаНачалаПримененияПостановления1137.Получить() Тогда

Но при каждом выполнении данного кода происходит обращение к базе данных.

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

· не вполне ясный цикл выполнения кода (например, при групповом перепроведении документов);

· получение строгого набора данных, необходимых не в данный момент, иногда невозможно или удается с трудом;

· использование уже кэшированных данных в различных формах/вызовах.

Модуль с повторным использованием возвращаемых значений

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

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

При выполнении кода осуществляется кэширование возвращаемых значений через значения переданных параметров. Таким образом это происходит непосредственно при выполнении кода

Узел1 = НашМодуль.ПолучитьУзелОбменаСБухгалтерией("0001");

Узел2 = НашМодуль.ПолучитьУзелОбменаСБухгалтерией("0002");

И один, и другой вызов приводят к выполнению соответствующей операции и возвращают разные ссылки. Однако уже при следующих вызовах узлы с кодом 0001 или 0002 будут возвращаться, не вызывая повторную операцию и, соответственно, не обращаясь к базе данных.

Значения будут кэшированы изолированно при каждом сеансе и на клиенте, и на сервере (это зависит от того, от какого модуля был совершен вызов, – клиентского или серверного). Все отработает безупречно в том случае, если в настройках прав доступа либо любой другой зависимости полученного значения есть какие-либо особенности.

Несколько НО

Как в любом правиле, в этом способе есть исключения. Не следует указывать сложные типы в параметрах функций, достаточно простых типа Дата, Число, Неопределенно и так далее. Не стоит пытаться указать в качестве параметров, к примеру, структуру, объект или таблицу значений. Результат в первый раз вы получите, но во второй раз уже ничего толкового не выйдет.

Возвращаемое значение может при этом быть любого типа.

Кроме этого, не забывайте обращать внимание на то, данные какого размера вы кэшируете, так как память сервера хоть и огромна, но не безгранична.

Фича или баг от 1С

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

При введении следующего кода:

ЗначениеСтруктура1 = НашМодуль.ПолучитьСтруктуруЗначенийРеквизитов(СсылкаНаОбъект);
ЗначениеСтруктура1.Наименование = "Новое наименование";
ЗначениеСтруктура2 = НашМодуль.ПолучитьСтруктуруЗначенийРеквизитов(СсылкаНаОбъект);

в ЗначениеСтруктура2.Наименование появится именно Новое наименование. Это может быть использовано для того, чтобы обновлять значения, которые действительно были изменены в базе данных, но неизвестно, сколько еще времени это можно будет делать. Потому как при создании типовых решений так делать нельзя.

Если были изменены закэшированные данные

Если в базе данных были изменены закэшированные значения, воспользоваться можно одним-единственным способом – методом ОбновитьПовторноИспользуемыеЗначения. В этом случае во всех модулях происходит сброс значений настроек всех функций. Отсутствует возможность обновления по одним каким-то значениям параметров, либо функциям, либо модулям.

Как осуществляется запрос в цикле

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

· Универсальные процедуры, которые возвращают реквизиты произвольных ссылок.

· Создание процедуры, которые возвращают значения констант по их имени. Кстати, такие процедуры есть в типовых версиях.

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

· Создание процедуры, которая будет выполнять запрос с одновременным кэшированием полученного результата (входящие параметры – текст запроса, несколько имен и значений параметров).

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

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


Модули платформы 1С:Предприятие 8.3, 8.2

Общие модули

Функции, которые объявлены с флагом "экспорт" в таком модуле, можно вызывать из любых мест конфигурации. Вызов делается через ИмяОбщегоМодуля.ИмяФункции().

В таких модулях отсутствует раздел переменных.

Выполнение общих модулей зависит от выставленных параметров в их свойствах:

Флаг "Глобальный"

Если этот флаг установлен, то контекст такого модуля становится глобальным. То есть при обращении к его экспортным функциям не нужно указывать имя модуля. Но имена его экспортных функций должны быть уникальными в пределах глобального контекста конфигурации.

Флаг "Сервер"

Функции такого модуля могут выполняться на сервере.

Флаг "Клиент (обычное приложение)"

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

Флаг "Клиент (управляемое приложение)"

Функции такого модуля могут выполняться на клиенте в режиме управляемого приложения.

Флаг "Вызов сервера"

Флаг доступен для модулей с установленным флагом "Сервер". Разрешает вызов на клиенте экспортных функций этого модуля (которые будут выполняться на сервере).

Флаг "Внешнее соединение"

Экспортные функции такого модуля могут быть вызваны при подключении из внешнего источника.

Флаг "Привилегированный"

В модуле с таким флагом будет отключена проверка прав. Подходит для повышения производительности или действий по администрированию.

Параметр "Повторное использование"

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

Модуль приложения

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

Не следует его перегружать, так как это влияет на время запуска приложения.

Модуль сеанса

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

Использовать его следует осторожно, так как модуль может выполняться несколько раз, а также выполняться без дальнейшего запуска базы. Выполняется до модулей приложения.

С уважением, (преподаватель и разработчик ).

Просмотров