Как устранить зависание при подключении к внешнему источнику данных (ВИД) в 1С:Предприятие

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

Интеграция систем на платформе «1С:Предприятие 8» с внешними базами данных — стандартная задача для современных корпоративных информационных систем. Для этих целей разработчики чаще всего используют встроенный механизм Внешних источников данных (ВИД). Это удобный инструмент, позволяющий работать с таблицами сторонних СУБД (MS SQL Server, PostgreSQL, Oracle, MySQL и др.) практически так же, как и с собственными объектами конфигурации 1С. В качестве альтернативного инструмента для передачи информации можно использовать подсистему выгрузки данных во внешнюю базу SQL.

Однако при активной эксплуатации интеграции разработчики нередко сталкиваются с крайне неприятным симптомом: подключение к внешней базе вроде бы проходит успешно, но первый же запрос на выборку или запись данных «подвисает» на неопределенный срок. При этом прямое подключение к СУБД под той же учетной записью (например, через SQL Server Management Studio) работает быстро и стабильно. Проанализируем, почему так происходит, и разберем по шагам, как решить эту проблему раз и навсегда.

Разбор клинического случая: Почему зависает СУБД?

В процессе обсуждения технической проблемы на форуме выяснилось, что первопричиной бесконечного зависания запросов к внешнему источнику данных является накопление открытых транзакций на стороне целевой СУБД. Давайте детально рассмотрим внутренние механизмы взаимодействия платформы 1С и SQL-сервера через ODBC-драйвер.

  1. Кэширование соединений (Connection Pooling). Платформа 1С в целях оптимизации производительности стремится повторно использовать ранее созданные физические каналы связи. При работе с внешними источниками данных открытые ODBC-соединения кэшируются на уровне сеанса пользователя 1С или рабочего процесса сервера (rphost). Если соединение не разорвано принудительно, оно остается активным на сервере баз данных и переходит в спящий режим (статус sleeping в MS SQL Server).
  2. Неявные транзакции (Implicit Transactions). В зависимости от версии СУБД, настроек конкретной базы данных и параметров используемого ODBC-драйвера, СУБД может автоматически открывать транзакцию при получении любого запроса (даже простого чтения SELECT). Этот режим называется неявными транзакциями.
  3. Накопление зависших блокировок. Если разработчик в коде 1С выполнил запрос к таблице внешнего источника данных, СУБД открыла транзакцию и наложила разделяемые блокировки (Shared Locks) на соответствующие строки или таблицы. Если после завершения работы с данными соединение не было разорвано явным образом через метод РазорватьСоединение(), транзакция остается открытой. Когда таких «спящих» транзакций накапливается критическое количество, СУБД начинает испытывать дефицит ресурсов, новые запросы выстраиваются в очередь ожидания блокировок (Lock Wait), и система полностью зависает.

Именно поэтому простая вставка вызова метода РазорватьСоединение() решает проблему: физический сеанс на стороне SQL корректно завершается, все связанные с ним незафиксированные транзакции автоматически откатываются, а занятые блокировки освобождаются.

Как на самом деле настроить таймауты для внешних источников данных

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

Рассмотрим подробнее ключевые параметры строки подключения, которые необходимо добавлять при динамическом формировании строки соединения:

Пример формирования строки подключения к MS SQL Server с установленным таймаутом соединения в 15 секунд:


СтрокаПодключения = "DRIVER={SQL Server};SERVER=MySqlServer;DATABASE=ExternalDB;UID=1c_user;PWD=SecretPassword;Connect Timeout=15;";
ВнешнийИсточник = ВнешниеИсточникиДанных.ИмяВашегоИсточника;
ВнешнийИсточник.УстановитьОбщуюСтрокуПодключения(СтрокаПодключения);

Блокировки данных и уровни изоляции транзакций в ВИД

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

Выясним, как это сделать:

  1. Откройте Конфигуратор 1С и найдите нужный ВнешнийИсточникДанных.
  2. Перейдите к свойствам конкретной таблицы этого источника.
  3. Найдите свойство Уровень изоляции транзакций.
  4. Установите значение Read Uncommitted (Грязное чтение).

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

Если же «грязное чтение» недопустимо по соображениям бизнес-логики, рекомендуется активировать на стороне целевой СУБД MS SQL режим версионирования строк — Read Committed Snapshot Isolation (RCSI). В этом случае читающие запросы 1С будут бесконфликтно читать данные из базы данных tempdb, не пересекаясь с пишущими транзакциями.

Шаблон правильной работы с транзакциями при записи

Если через внешний источник данных вы выполняете не только чтение, но и изменение (запись) информации, критически важно оборачивать процесс в явную транзакцию 1С с обязательным откатом в случае возникновения непредвиденных ошибок СУБД.

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


ВнешнийИсточник = ВнешниеИсточникиДанных.ИмяВашегоИсточника;

// 1. Устанавливаем соединение с внешней базой
Попытка
    ВнешнийИсточник.УстановитьСоединение();
Исключение
    ЗаписьЖурналаРегистрации("Интеграция.Подключение",
        УровеньЖурналаРегистрации.Ошибка, , ,
        "Не удалось подключиться к внешнему источнику: " + ОписаниеОшибки());
    Возврат;
КонецПопытки;

// 2. Начинаем явную транзакцию на стороне внешней СУБД
ВнешнийИсточник.НачатьТранзакцию();

Попытка
    // Выполняем операции записи данных
    НоваяЗапись = ВнешнийИсточник.Таблицы.ИмяТаблицы.СоздатьОбъект();
    НоваяЗапись.КодОбъекта = "12345";
    НоваяЗапись.Наименование = "Тестовая запись через ВИД";
    НоваяЗапись.Записать();
    
    // Если все операции прошли успешно, фиксируем изменения в СУБД
    ВнешнийИсточник.ЗафиксироватьТранзакцию();
    
Исключение
    // В случае ЛЮБОЙ ошибки обязательно производим отмену транзакции,
    // чтобы не оставить блокировки активными в памяти SQL-сервера
    Если ВнешнийИсточник.ТранзакцияАктивна() Тогда
        ВнешнийИсточник.ОтменитьТранзакцию();
    КонецЕсли;
    
    ЗаписьЖурналаРегистрации("Интеграция.Запись",
        УровеньЖурналаРегистрации.Ошибка, , ,
        "Ошибка при записи данных: " + ОписаниеОшибки());
КонецПопытки;

// 3. Явно разрываем физическое соединение с базой данных
ВнешнийИсточник.РазовратьСоединение();

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

Нюансы авторизации в клиент-серверном режиме

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

Выясним причину этой проблемы:

Для исключения подобных ситуаций при серверной работе рекомендуется использовать явную авторизацию СУБД (SQL Server Authentication) с указанием логина и пароля пользователя базы данных в строке подключения, либо предварительно предоставить полные сетевые права и права СУБД для учетной записи службы USR1CV8.

← На главную