Как «на лету» проверить актуальность COM-подключения ADODB и настроить переподключение к резервному SQL-серверу?

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

При работе с внешними базами данных через COM-объект ADODB.Connection часто возникает ситуация, когда установленное соединение становится неактуальным. Это может произойти из-за сетевых сбоев, плановых работ на стороне SQL-сервера или его временной недоступности. Если ваша задача требует стабильной работы (например, формирование сложного отчета, использующего данные из внешнего источника), необходимо предусмотреть механизм оперативной проверки связи и автоматического переключения на резервный сервер. Разберем, как реализовать такую проверку «на лету» и какие нюансы следует учитывать.

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

Рассмотрим типичную ситуацию. У нас есть функция, которая инициализирует подключение к основному серверу, а в случае неудачи — к резервному. Проблема заключается в том, что после успешного открытия соединения (метод Open()) объект ADODB.Connection может храниться в памяти долгое время. Если за этот период сервер «упал» или соединение было разорвано со стороны SQL, объект в 1С все еще будет существовать, но любая попытка выполнить запрос приведет к фатальной ошибке.

Многие разработчики пытаются использовать свойство State(). Однако важно понимать: State возвращает состояние объекта на основе последней успешной операции. Если физический разрыв произошел мгновение назад, свойство может продолжать возвращать значение 1 (соответствует константе adStateOpen), пока вы не попытаетесь отправить данные в канал.

Решение 1: Метод «легкого запроса» (Ping Query)

Проанализируем наиболее надежный вариант проверки — выполнение максимально простого SQL-запроса непосредственно перед выполнением основных расчетов. Это позволяет убедиться, что канал передачи данных активен и база данных готова к работе.

Рассмотрим пример реализации функции проверки:


Функция ПодключениеАктуально(ТекущееСоединение)
    
    Если ТекущееСоединение = Неопределено Тогда
        Возврат Ложь;
    КонецЕсли;

    // Проверяем статус объекта в памяти
    Если ТекущееСоединение.State() = 0 Тогда
        Возврат Ложь;
    КонецЕсли;

    Попытка
        // Выполняем максимально легкий запрос к серверу
        // CommandTimeout ставим минимальный, чтобы не вешать интерфейс
        ТекущееСоединение.Execute("SELECT 1");
        Возврат Истина;
    Исключение
        // Если запрос не прошел, значит связь потеряна
        Возврат Ложь;
    КонецПопытки;

КонецФункции

В этом примере мы используем запрос SELECT 1. Он практически не нагружает сервер, но гарантирует, что сессия активна. Если функция возвращает Ложь, программа должна инициировать процедуру переподключения к резервному узлу.

Решение 2: Проверка состояния базы данных через системные таблицы

Иногда сервер доступен, но конкретная база данных переведена в режим OFFLINE или SINGLE_USER из-за технических работ. Чтобы понять, что пора переключаться на реплику, можно проверить состояние базы в системном представлении sys.databases. Разберем, как это реализовать:


ТекстЗапроса = "SELECT t.state_desc FROM sys.databases t WHERE t.name = 'ИмяВашейБазы'";
Recordset = Соединение.Execute(ТекстЗапроса);

Если СокрЛП(Recordset.Fields("state_desc").Value) <> "ONLINE" Тогда
    // База недоступна для полноценной работы, нужно переподключение
    ПереподключитьсяКРезерву();
КонецЕсли;

Важный нюанс: этот метод сработает только в том случае, если само соединение с сервером еще живо. Если упал весь SQL-сервер, обращение к sys.databases вызовет исключение, которое также нужно обрабатывать через Попытка — Исключение.

Решение 3: Стратегия «коротких» соединений

Проанализируем архитектурный подход. Если специфика вашей задачи позволяет, лучше не хранить объект Connection между вызовами. В среде SQL Server широко используется механизм Connection Pooling (пул соединений). Это означает, что когда вы вызываете Open() и Close(), физическое соединение не всегда разрывается мгновенно — драйвер ADO сохраняет его в пуле для повторного использования.

Если ваши расчеты не зависят от состояния сессии (например, вы не используете локальные временные таблицы SQL, начинающиеся с символа #), то наиболее надежным вариантом будет создание нового подключения на каждую операцию. Это автоматически снимет вопрос об актуальности «старого» соединения.

Особенности работы с временными таблицами

Выясним причину, по которой иногда нельзя просто переподключиться. Если ваш алгоритм в 1С строит сложную логику на стороне SQL с использованием #temp_tables, то переподключение уничтожит эти таблицы, так как они живут только в рамках одной сессии (одного конкретного соединения).

В такой ситуации разберем следующий алгоритм действий:

  1. Перед началом каждого этапа расчета вызываем проверку State() и выполняем тестовый запрос.
  2. Если проверка не прошла, выполняем полную инициализацию данных заново на резервном сервере.
  3. Используем конструкцию cnn.Properties("Server Name").Value для понимания того, на каком сервере мы сейчас находимся, чтобы в будущем вернуть пользователя на основной сервер, как только он станет доступен.

Технические рекомендации по настройке строки подключения

Чтобы сделать процесс переподключения более быстрым и стабильным, обратим внимание на параметры строки подключения (ConnectionString):

Рассмотрим пример настройки свойств объекта перед открытием:


cnn = Новый COMОбъект("ADODB.Connection");
cnn.ConnectionString = "Provider=MSOLEDBSQL;Data Source=" + ИмяСервера + ";Initial Catalog=" + ИмяБазы + ";User ID=" + Логин + ";Password=" + Пароль + ";";
cnn.ConnectionTimeOut = 30; // Время ожидания самого подключения
cnn.CommandTimeOut = 600;   // Время ожидания выполнения тяжелых запросов
cnn.CursorLocation = 3;     // adUseClient
cnn.Open();

Использование CursorLocation = 3 (клиентский курсор) часто помогает избежать проблем с блокировками на сервере и позволяет более гибко работать с полученным набором записей (Recordset) внутри 1С.

Таким образом, комбинируя периодическую проверку «легким» запросом и грамотную обработку исключений, мы можем создать отказоустойчивую систему взаимодействия с внешними данными, которая незаметно для пользователя переключится на резервный сервер в случае аварии.

← На главную