При разработке сложных интеграционных решений между 1С и внешними системами (например, сайтами на базе 1С-Битрикс) у разработчиков часто возникает соблазн использовать низкоуровневые инструменты СУБД. Напрямую работать с таблицами базы данных через хранимые процедуры (Stored Procedures, SP) и триггеры кажется быстрым и производительным решением. Однако такой подход таит в себе множество скрытых угроз для стабильности и производительности всей системы.
В рамках этой статьи мы подробно разберем, почему внедрение кастомного SQL-кода непосредственно в рабочую базу 1С является опасной практикой, к каким последствиям это может привести и какие современные архитектурные паттерны следует использовать для надежного обмена данными.
Давайте проанализируем, почему создание собственных объектов на уровне СУБД в рабочей базе 1С крайне не рекомендуется:
.dt — платформа упаковывает только те данные и структуры, о которых она «знает» на уровне метаданных. Все сторонние хранимые процедуры, триггеры, представления (View) и кастомные индексы, созданные непосредственно в СУБД, будут проигнорированы. При последующем развертывании базы из этого .dt-файла вы получите чистую структуру без ваших наработок._tmp), переносит туда накопленные данные, удаляет старую таблицу и переименовывает временную. Если ваша хранимая процедура жестко ссылалась на имя физической таблицы (например, _InfoReg1234), то в момент удаления таблицы СУБД выдаст ошибку компиляции зависимого объекта или вовсе заблокирует процесс обновления 1С, что приведет к аварийному завершению и повреждению базы.Если бизнес-требования все же диктуют необходимость работы на уровне СУБД, рассмотрим, как правильно локализовать эти решения.
Если обойтись без использования хранимых процедур невозможно (например, требуется выполнять сложную аналитическую обработку на стороне SQL-сервера или осуществлять прямую запись в базу данных Битрикса через связку серверов Linked Servers), категорически нельзя размещать эти объекты внутри рабочей БД 1С.
Для этих целей мы можем применить паттерн служебной базы данных:
Service_Integration_DB).ADODB.Connection), отправляя туда необходимые порции информации.Такой подход полностью изолирует рабочую базу 1С, гарантирует успешное прохождение обновлений и исключает риск потери кастомного SQL-кода при административных работах.
Часто разработчики пытаются реализовать отправку данных во внешнюю систему непосредственно в момент записи объекта (например, в модуле объекта внутри процедуры ПриЗаписи или в подписке на событие). Разберем по шагам, почему это является критической ошибкой проектирования.
Когда пользователь проводит документ или записывает элемент справочника, вся цепочка кода выполняется внутри одной транзакции базы данных. Если внутри этой транзакции мы выполняем прямой HTTP-запрос к сайту Битрикса, мы сталкиваемся со следующими проблемами:
ПриЗаписи транзакция еще не завершена. В любой момент последующий код (например, проверка в подписке на событие или контроль остатков при проведении) может отменить запись (установить параметр Отказ = Истина). В этом случае транзакция 1С откатится, новые данные в базу не запишутся, но ваш HTTP-запрос уже улетел на сайт, и Битрикс получил неактуальные данные.Read Committed, фоновое задание не увидит новые данные до тех пор, пока основная транзакция, запустившая его, не будет успешно зафиксирована (закомичена). Фоновое задание либо сразу упадет с ошибкой «Объект не найден», либо попытается прочитать данные и зависнет, ожидая снятия блокировки с записываемой строки.Ниже мы рассмотрим надежные, проверенные временем паттерны, которые позволяют избежать этих проблем.
Это самый надежный и стандартный способ интеграции в экосистеме 1С. Суть метода заключается в разделении процесса регистрации изменений и процесса их непосредственной отправки.
Разберем пошаговую реализацию этого паттерна:
Шаг 1. Создаем в конфигураторе новый План обмена (назовем его ИнтеграцияСБитрикс). В составе плана обмена отмечаем те объекты метаданных (справочники, регистры), изменения которых нам необходимо отслеживать.
Шаг 2. В транзакции записи объекта мы регистрируем только сам факт изменения. Это легкая и быстрая операция, которая не создает блокировок. Для этого можно использовать подписку на событие ПриЗаписи объекта:
Процедура ЗарегистрироватьИзмененияПриЗаписи(Источник, Отказ, Замещение) Экспорт
Если Отказ Тогда
Возврат;
КонецЕсли;
// Получаем предопределенный узел нашего плана обмена
УзелИнтеграции = ПланыОбмена.ИнтеграцияСБитрикс.НайтиПоКоду("BitrixSite");
Если ЗначениеЗаполнено(УзелИнтеграции) Тогда
// Регистрируем изменение для конкретного узла
ПланыОбмена.ЗарегистрироватьИзменения(УзелИнтеграции, Источник.Ссылка);
КонецЕсли;
КонецПроцедуры
Шаг 3. Создаем регламентное задание, которое запускается в фоновом режиме по расписанию (например, каждые 10–30 секунд) вне транзакций пользователей. Оно считывает зарегистрированные изменения, формирует пакет данных и отправляет его во внешнюю систему:
Процедура ВыполнитьВыгрузкуВБитрикс() Экспорт
УзелИнтеграции = ПланыОбмена.ИнтеграцияСБитрикс.НайтиПоКоду("BitrixSite");
Если Не ЗначениеЗаполнено(УзелИнтеграции) Тогда
Возврат;
КонецЕсли;
// Выбираем изменения порциями, чтобы не перегружать оперативную память
ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(УзелИнтеграции, 50);
Пока ВыборкаИзменений.Следующий() Цикл
ТекущиеДанные = ВыборкаИзменений.Получить();
// Формируем пакет данных для отправки по API
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("UUID", Строка(ТекущиеДанные.Ссылка.УникальныйИдентификатор()));
ПараметрыЗапроса.Вставить("Name", ТекущиеДанные.Наименование);
// Преобразуем структуру в JSON-строку
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
СтрокаJSON = ЗаписьJSON.Закрыть();
// Выполняем отправку через HTTP-соединение
РезультатОтправки = ОтправитьДанныеНаСайт(СтрокаJSON);
Если РезультатОтправки Тогда
// Очищаем регистрацию только в случае подтверждения успешного приема
ПланыОбмена.УдалитьРегистрациюИзменений(УзелИнтеграции, ТекущиеДанные.Ссылка);
Иначе
// В случае ошибки останавливаем итерацию, повторим попытку при следующем запуске задания
ЗаписатьВЖурналРегистрации("Интеграция", УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось отправить объект: " + Строка(ТекущиеДанные.Ссылка));
Прервать;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот подход гарантирует 100% доставку данных. Даже если сайт Битрикса упадет или возникнут проблемы с интернет-соединением, изменения никуда не пропадут: они будут оставаться зарегистрированными на узле плана обмена до тех пор, пока связь не восстановится и регламентное задание успешно их не обработает.
Если использование планов обмена кажется избыточным или требуется логировать дополнительные параметры (например, количество попыток отправки или подробный текст ошибки непосредственно в интерфейсе 1С), отличной альтернативой выступает создание служебного регистра сведений.
Рассмотрим структуру такого решения:
ОчередьИнтеграцииСБитрикс.Объект (ЛюбаяСсылка).СтатусВыгрузки (Перечисление: Новый, Ошибка, Выгружено), КоличествоПопыток (Число) и ТекстОшибки (Строка неограниченной длины).При записи бизнес-объекта в этот регистр помещается новая запись со статусом Новый. Фоновое регламентное задание считывает записи из регистра со статусами Новый и Ошибка (если лимит попыток еще не исчерпан), производит попытку отправки и по результатам обновляет статус или удаляет успешно обработанные строки.
Это исключает прямое влияние внешних сетевых факторов на транзакции пользователей и позволяет детально контролировать процесс обмена данными непосредственно в информационной базе 1С.