Как использовать план обмена без РБД для регистрации и выгрузки изменений

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

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

Зачем использовать планы обмена без РИБ?

План обмена в 1С выполняет две ключевые функции:

  1. Регистрация изменений. Платформа автоматически отслеживает создание, изменение и удаление объектов (документов, справочников, регистров), указанных в составе плана обмена, и записывает эти события в специальную служебную таблицу регистрации изменений.
  2. Определение состава обмена. Мы можем гибко настраивать, какие именно типы данных должны мигрировать между узлами.

Если мы не используем РИБ, платформа не накладывает жестких ограничений на идентичность конфигураций в базах-участниках обмена и не управляет передачей конфигурации. Это развязывает нам руки: мы можем обмениваться данными между совершенно разными прикладными решениями (например, «1С:Бухгалтерия» и «1С:Розница» или ERP и мобильным приложением).

Критическая уязвимость схемы «выгрузил — очистил регистрацию» (Race Condition)

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

  1. Программа выбирает все зарегистрированные изменения по узлу плана обмена.
  2. Данные сериализуются и записываются в файл (или отправляются по API).
  3. Выполняется полная очистка регистрации изменений с помощью метода ПланыОбмена.УдалитьРегистрациюИзменений(Узел).

В чем заключается смертельная опасность этого подхода?

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

Когда выгрузка завершится и ваш код вызовет метод ПланыОбмена.УдалитьРегистрациюИзменений(Узел), платформа удалит вообще все зарегистрированные изменения для данного узла — включая то новое изменение, которое произошло во время выгрузки. Как результат, этот измененный объект никогда не попадет во внешнюю систему. Произойдет тихая и необратимая потеря данных.

Правильное решение: использование механизма номеров сообщений

Чтобы раз и навсегда решить проблему конкурентного доступа и потери данных (Race Condition), платформа 1С предоставляет механизм номеров сообщений (номеров пакетов). Номера сообщений служат для разграничения изменений, которые уже попали в текущую транзакцию выгрузки, и тех, которые возникли непосредственно в процессе выгрузки или после нее.

Разберем правильный алгоритм работы по шагам:

Шаг 1. Получение изменений и фиксация номера отправленного сообщения

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


// Получаем объект узла для изменения номера отправленного сообщения
УзелОбъект = СсылкаНаУзел.ПолучитьОбъект();
НовыйНомерОтправленного = УзелОбъект.НомерОтправленного + 1;

// Начинаем транзакцию для обеспечения согласованности данных
НачатьТранзакцию();
Попытка
    // Записываем новый номер в узел
    УзелОбъект.НомерОтправленного = НовыйНомерОтправленного;
    УзелОбъект.Записать();
    
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение "Не удалось зафиксировать номер отправленного сообщения: " + ОписаниеОшибки();
КонецПопытки;

// Выбираем изменения, привязывая их к новому номеру сообщения
ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(СсылкаНаУзел, НовыйНомерОтправленного);

Метод ПланыОбмена.ВыбратьИзменения() делает важнейшую вещь: он берет все зарегистрированные на данный момент изменения и сопоставляет их с числом НовыйНомерОтправленного. Если во время работы нашего цикла выгрузки пользователи изменят какие-то объекты, эти новые изменения получат признак номера сообщения NULL и не будут затронуты последующей очисткой.

Шаг 2. Выгрузка данных

Мы обходим выборку изменений и записываем данные в файл, XML, JSON или отправляем через HTTP/web-сервисы:


Пока ВыборкаИзменений.Следующий() Цикл
    ДанныеОбъекта = ВыборкаИзменений.Получить();
    
    // Выполняем экспорт данных (например, через КД или EnterpriseData)
    // ЗаписатьДанныеВПоток(ДанныеОбъекта);
КонецЦикла;

Шаг 3. Удаление регистрации изменений после успешной отправки

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


// Удаляем только те изменения, которые вошли в пакет с НомеромОтправленного
ПланыОбмена.УдалитьРегистрациюИзменений(СсылкаНаУзел, НовыйНомерОтправленного);

Этот метод удалит из таблицы регистрации только те записи, у которых номер сообщения совпадает с переданным параметром. Новые изменения, возникшие во время выгрузки (с номером сообщения NULL), останутся нетронутыми и будут выгружены при следующем сеансе обмена. Мы полностью защитили систему от потери данных!

Организация гарантированной доставки (Квитирование)

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

Для решения этой проблемы в обменах без РИБ реализуют механизм квитирования (двухэтапного подтверждения доставки):

  1. Источник формирует файл выгрузки, присваивая ему номер сообщения (например, № 15). Регистрацию изменений в источнике на этом этапе не удаляют.
  2. Приемник считывает файл № 15, успешно загружает данные в свою базу без ошибок. После успешного завершения транзакции загрузки приемник генерирует ответный файл-квитанцию (или отправляет HTTP-запрос), в котором передает статус: "Сообщение № 15 успешно загружено".
  3. При следующем сеансе обмена Источник сначала ищет и считывает квитанцию от приемника. Если в ней написано, что сообщение № 15 принято, источник выполняет очистку: ПланыОбмена.УдалитьРегистрациюИзменений(СсылкаНаУзел, 15); Если квитанция не пришла (или пришла информация об ошибке), источник не удаляет регистрацию. При очередном запуске обмена все эти данные снова попадут в новый файл выгрузки.

План обмена против Регистра сведений: почему «свое казино» — плохая идея

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

Выясним, почему этот подход (метко названный на форумах «своим казино со своим блэкджеком») является архитектурно неверным:

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

Современный стандарт разработки: БСП и формат EnterpriseData

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

Резюмируем: Использование планов обмена без признака РИБ — это мощный, быстрый и правильный инструмент для регистрации изменений. Главное — всегда использовать штатный механизм номеров сообщений платформы 1С для предотвращения потери данных и по возможности опираться на проверенные временем механизмы БСП.

← На главную