При работе с 1С:Шиной часто возникает задача интеграции внешних SQL-баз с конфигурациями 1С (например, 1С:ЗУП). Стандартный компонент SQL-коннектор при срабатывании по таймеру обычно забирает результат SQL-запроса целиком и помещает его в тело одного сообщения. Если в таблице 100 записей, в 1С придет один массив. Однако для корректной обработки, логирования и управления очередями часто требуется правило: одна строка таблицы — одно сообщение в шине. Разберем подробно, как реализовать такой сценарий несколькими способами.
Проанализируем ситуацию: стандартный SQL-коннектор имеет ограниченный набор обработчиков, которые не позволяют "размножить" сообщения внутри самого узла. Наиболее профессиональным решением является замена связки Таймер + SQL-коннектор на один узел Программный источник. Этот компонент позволяет написать произвольный код на языке 1C:Executor (встроенный язык Шины), который будет самостоятельно подключаться к базе и генерировать сообщения в цикле.
Рассмотрим алгоритм настройки Программного источника:
Посмотрим на пример кода, который реализует перебор строк таблицы и отправку каждой строки как отдельного сообщения:
// Пример логики внутри Программного источника
метод ВыполнитьОпросБД()
пер Соединение = СУБД.Подключиться("jdbc:sqlserver://server;databaseName=db", "user", "pass")
пер Запрос = Соединение.СоздатьЗапрос("SELECT id, data FROM IntegrationTable WHERE Processed = 0")
пер Результат = Запрос.Выполнить()
пока Результат.Следующий() цикл
// Формируем новое сообщение интеграции
пер НовоеСообщение = новый СообщениеИнтеграции()
// Сериализуем строку в JSON или XML
пер Тело = { "id": Результат.id, "content": Результат.data }
НовоеСообщение.УстановитьТелоИзСтроки(СериализоватьJSON(Тело))
// Отправляем сообщение в исходящие линии узла
ЭтотУзел.ОтправитьВУзлы(НовоеСообщение, ЭтотУзел.Схема.Узлы.КаналПриемник)
// Сразу помечаем запись в SQL как обработанную, чтобы избежать дублей
Соединение.ВыполнитьКоманду("UPDATE IntegrationTable SET Processed = 1 WHERE id = " + Результат.id)
конецЦикла
Соединение.Закрыть()
конецМетода
Преимущество этого метода заключается в том, что каждое сообщение становится независимой единицей в очереди 1С:Шины. Если обработка 10-й записи в 1С:ЗУП завершится ошибкой, это не повлияет на доставку остальных 99 сообщений.
Если вы не хотите отказываться от удобства визуальной настройки SQL-коннектора, проанализируем вариант с последующей трансформацией. В этой схеме SQL-коннектор забирает все данные, а следующий за ним узел Скрипт "разрезает" их.
Разберем по шагам реализацию этой схемы:
Таймер -> SQL-коннектор -> Скрипт.SQL-коннекторе настроим запрос так, чтобы он возвращал данные в формате JSON или XML.Скрипт напишем код, который перебирает входящий массив данных.Пример кода для узла Скрипт:
// Входящее сообщение содержит массив структур
пер ВходящееСообщение = Контекст.Сообщение
пер МассивДанных = ДесериализоватьJSON(ВходящееСообщение.ПолучитьТелоКакСтроку())
для каждого Строка из МассивДанных цикл
пер СообщениеДляОтправки = новый СообщениеИнтеграции()
СообщениеДляОтправки.УстановитьТелоИзСтроки(СериализоватьJSON(Строка))
// Отправляем в следующий узел по цепочке
Контекст.Отправить(СообщениеДляОтправки, "ВыходнойКанал")
конецЦикла
// Оригинальное "большое" сообщение поглощается и не идет дальше
Контекст.ПодтвердитьОбработку()
Важно помнить, что при таком подходе возрастает нагрузка на оперативную память Шины, если выборка из SQL очень большая (например, десятки тысяч строк), так как всё "большое" сообщение должно быть загружено в память перед разделением.
Рассмотрим ситуацию, когда начальство или технические регламенты требуют максимально упростить схему в Шине. Мы можем изменить саму логику SQL-запроса, чтобы SQL-коннектор за один такт таймера всегда выбирал ровно одну запись.
Проанализируем этот подход:
SQL-коннекторе напишем запрос с ограничением выборки: SELECT TOP 1 * FROM Table WHERE IsProcessed = 0 ORDER BY CreateDate.IsProcessed = 1 в исходной таблице.Выясним причину популярности этого метода: он не требует сложного программирования на стороне Шины и использует стандартные кубики. Однако он создает избыточную нагрузку на SQL-сервер из-за постоянных коротких запросов, даже когда данных нет.
Подведем итог нашему анализу и выберем оптимальный путь:
TOP 1, но следите за нагрузкой на БД.Во всех случаях не забывайте про Retry Policy (политику повторов). Когда одна запись SQL превращается в одно сообщение Шины, вы получаете полный контроль над качеством доставки: Шина будет пытаться доставить каждое конкретное письмо до тех пор, пока ЗУП не подтвердит его получение, не блокируя при этом работу с другими записями.