Как исправить ошибку при повторном подключении к базе Firebird (GDB) через ADO в 1С?

Программист IT и автоматизация бизнеса
← На главную

Многие разработчики сталкиваются с типичной проблемой при интеграции 1С с внешними базами данных, такими как Firebird или InterBase. Первое подключение к файлу базы данных проходит успешно, данные считываются, но при попытке повторного подключения или выполнения нового запроса возникает ошибка: Произошла исключительная ситуация (ADODB.Recordset): Аргументы имеют неверный тип, выходят за пределы допустимого диапазона или вступают в конфликт друг с другом. Иногда эта ошибка может звучать иначе: Операция не допускается, если объект закрыт.

Давайте подробно разберем, почему возникает эта проблема и как ее правильно решить, чтобы обеспечить стабильную работу вашей интеграции.

Проанализируем причины возникновения ошибки

Основная причина кроется во взаимодействии платформы 1С, технологии ADO (ActiveX Data Objects) и драйверов баз данных. Рассмотрим основные факторы:

  1. Особенности пула соединений (Connection Pooling). По умолчанию ADO кэширует открытые подключения для экономии ресурсов. Когда мы вызываем метод Close() и присваиваем переменной соединения значение Неопределено, физического разрыва связи с БД часто не происходит. Соединение возвращается в пул. При повторном обращении 1С достает из пула «полузакрытое» соединение, внутреннее состояние которого рассинхронизировано с драйвером. Это и вызывает конфликт типов аргументов или ошибку закрытого объекта при попытке инициализировать новый ADODB.Recordset.
  2. Некорректное освобождение COM-объектов. В 1С присвоение переменной значения Неопределено не всегда приводит к мгновенной сборке мусора и удалению объекта из памяти платформы. Если старый объект набора записей или незакрытая транзакция продолжают «висеть» в памяти рабочего процесса, новое подключение неизбежно вступит с ними в конфликт.
  3. Специфика драйверов Firebird. Бесплатные или устаревшие версии ODBC/OLE DB драйверов Firebird имеют известные недоработки при многократном переподключении и работе с пулом соединений в рамках одного сеанса.

Вариант 1: Изменение подхода к выполнению запроса (использование ADODB.Command)

Вместо того чтобы передавать текст запроса напрямую в метод открытия рекордсета, давайте перепишем код с использованием промежуточного объекта ADODB.Command. Также перед открытием соединения зададим дополнительные параметры курсора, таймаута и режима работы. Посмотрим на пример правильной инициализации:


// 1. Настраиваем и открываем соединение
Connection = Новый COMОбъект("ADODB.Connection");
Connection.ConnectionString = "Driver=Firebird/InterBase(r) driver;" +
                              "Dbname=" + СокрЛП(Объект.ПутьКФайлу) + ";" + 
                              "UID=" + СокрЛП(Объект.Пользователь) + ";" + 
                              "PWD=" + СокрЛП(Объект.Пароль);

Connection.ConnectionTimeOut = 20;
Connection.CursorLocation = 1; 
Connection.Mode = 1;

Попытка
    Connection.Open();
    Сообщить("Успешное подключение");
Исключение
    Сообщить("Подключение к БД не установлено. Ошибка: " + ОписаниеОшибки());
    Connection = Неопределено;
    Возврат;
КонецПопытки;

// 2. Используем ADODB.Command для выполнения запроса
Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = Connection;
Команда.CommandText = "Select produce.id From produce Where produce.isactive = 1";

НаборЗаписей = Новый COMОбъект("ADODB.RecordSet");
Попытка
    НаборЗаписей = Команда.Execute();
    // Обход результатов выборки...
Исключение
    ЗаписьЖурналаРегистрации("ВнешняяБД.ОшибкаЗапроса", УровеньЖурналаРегистрации.Ошибка,,, Команда.CommandText + Символы.ПС + ОписаниеОшибки());
КонецПопытки;

Вариант 2: Отключение пула соединений в строке подключения

Чтобы заставить ADO каждый раз создавать новое, гарантированно «чистое» физическое соединение, мы можем отключить кэширование на уровне драйвера. Для этого добавим в строку подключения (в свойство ConnectionString) специальные параметры. В зависимости от версии и типа используемого драйвера, попробуйте добавить параметр Pooling=False или OLE DB Services = -2 (а в некоторых случаях -4). Это заставит подсистему принудительно обрывать физическую связь при вызове метода закрытия.

Вариант 3: Правильная очистка объектов и закрытие транзакций

Посмотрим на то, как мы завершаем работу с объектами ADO. Перед закрытием объекта Recordset крайне полезно принудительно отвязать его от текущего соединения. Присвоим свойству ActiveConnection значение Неопределено (или Null), и только после этого вызовем метод Close().

Также важно помнить о механизме транзакций. Если драйвер неявно открывает транзакцию (например, при чтении данных с определенным уровнем изоляции), ее нужно явно завершить, вызвав методы Commit или Rollback у объекта Connection. Соединение с незавершенной транзакцией, вернувшееся в пул, гарантированно вызовет ошибку при попытке повторного использования в следующем цикле работы 1С.

Вариант 4: Архитектурные решения и штатные механизмы 1С

Разберем наиболее правильные архитектурные подходы, которые позволят избежать проблемы в корне:

  1. Однократное подключение. Не открывайте и не закрывайте соединение ADODB.Connection внутри цикла или при каждом отдельном мелком запросе. Установите соединение один раз (например, при открытии формы или старте обработки), сохраните его в переменную модуля, выполняйте через него все необходимые операции и закрывайте только при полном окончании работы с формой.
  2. Использование Внешних источников данных (ВИД). Вместо ручной работы с COM-объектами воспользуйтесь стандартным механизмом платформы 1С — деревом метаданных «Внешние источники данных». Этот механизм работает на уровне сервера приложений 1С. Он самостоятельно и корректно управляет пулом соединений, транзакциями и выполняет маппинг типов данных. Это полностью снимает проблему «зависания» сеансов ADO.
  3. Альтернативные драйверы. Если вы вынуждены работать именно через прямое COM-соединение, рассмотрите возможность использования коммерческих OLE DB провайдеров (например, от компании LCPI). Они разрабатывались специально под особенности Firebird/InterBase и значительно стабильнее работают с пулом потоков, а также не имеют проблем с кодировками при передаче кириллицы.

Применив один или несколько из описанных подходов, вы сможете обеспечить стабильный и бесперебойный обмен данными между 1С и внешними базами.

← На главную