При переносе обработок 1С, взаимодействующих с файловыми базами данных Microsoft Access (форматы .mdb и .accdb), с локального компьютера разработчика на промышленный сервер под управлением 64-разрядных операционных систем (таких как Windows Server 2008 R2 или Windows Server 2012/2016), специалисты часто сталкиваются со специфическими ошибками. Две самые распространенные из них: отсутствие или несовместимость OLE DB / ODBC драйверов (сообщение «Источник данных не найден и не указан драйвер, используемый по умолчанию») и сбой активации COM-объектов (сообщение «Класс не зарегистрирован» при создании ADODB.Command).
В этой статье мы подробно разберем природу возникновения этих ошибок, проанализируем влияние разрядности процессов на работу драйверов баз данных и пошагово настроим стабильное подключение к файлам СУБД Access из среды 1С.
Рассмотрим типичный сценарий. На локальном компьютере программиста (например, под управлением Windows 7) обработка 1С успешно подключается к файлу базы данных СУБД Access и выбирает из нее данные. Однако при запуске этой же обработки на сервере под управлением Windows Server 2008 R2 выполнение кода прерывается на строке открытия соединения:
Connection.Open(СтрокаПодключения);
Система возвращает исключение: «Произошла исключительная ситуация (Microsoft OLE DB Provider for ODBC Drivers): [Microsoft][Диспетчер драйверов ODBC] Источник данных не найден и не указан драйвер, используемый по умолчанию».
Выясним главную причину этого сбоя. Она кроется в конфликте разрядности (битности) операционной системы, платформы 1С и установленных в системе драйверов баз данных. На 64-битных операционных системах сосуществуют две изолированные среды исполнения программ:
C:\Program Files, системные библиотеки в C:\Windows\System32.C:\Program Files (x86), а системные библиотеки — в папке C:\Windows\SysWOW64.Если код 1С выполняется в 32-битном процессе (например, запущен 32-битный тонкий клиент или база работает в файловом режиме под управлением 32-битной платформы), то операционная система разрешает загружать только 32-битные COM-объекты и драйверы. Если же код выполняется на стороне 64-битного сервера приложений 1С (например, в фоновом задании или при вызове серверного метода &НаСервере), то операционная система потребует исключительно 64-битные версии драйверов.
Очень часто разработчики используют устаревший способ подключения через драйверы ODBC. Строка подключения при этом выглядит следующим образом:
СтрокаПодключения = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=" + ФайлБазы;
Использование диспетчера драйверов ODBC на серверах крайне не рекомендуется, так как оно требует ручной настройки источников данных (DSN) внутри операционной системы и часто приводит к путанице из-за существования двух разных утилит конфигурирования: 64-битной (odbcad32.exe в папке System32) и 32-битной (в папке SysWOW64).
Для стабильной работы с файлами СУБД Access мы перейдем на использование технологии OLE DB. Вместо драйверов ODBC мы применим специализированные провайдеры (поставщики данных). Проанализируем два основных варианта:
.mdb (Access 97-2003). Важно помнить: этот провайдер является строго 32-битным. В 64-битных процессах он физически отсутствует и работать не будет..mdb, так и новый .accdb. Провайдер ACE поставляется как в 32-битной, так и в 64-битной редакциях, что делает его универсальным решением для серверов.Сформируем корректную строку подключения с использованием провайдера ACE:
СтрокаПодключения = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ФайлБазы + ";Persist Security Info=False;";
Чтобы понять, какие именно OLE DB провайдеры установлены в вашей операционной системе и доступны для платформы 1С, проведем простой и надежный эксперимент с помощью технологических файлов связи данных (файлов с расширением .udl).
Разберем этот процесс по шагам:
test_connection.udl.test_connection.udl, нажмите на него правой кнопкой мыши и выберите пункт Свойства.Поскольку вы открыли этот диалог из-под запущенного процесса 1С, вы увидите ровно тот набор OLE DB провайдеров, который доступен платформе вашей разрядности в данный момент.
Попробуйте выбрать поочередно поставщиков Microsoft Jet 4.0 OLE DB Provider или Microsoft Office 12.0 Access Database Engine OLE DB Provider, перейдите на вкладку «Соединение» (Connection), укажите путь к вашему файлу базы данных Access и нажмите кнопку «Проверить соединение».
После успешной проверки закройте окно, сохранив изменения. Откройте файл test_connection.udl обычным текстовым редактором (например, Блокнотом). Внутри файла вы увидите готовую, протестированную и гарантированно рабочую строку подключения, которую можно скопировать прямо в модуль 1С.
Если при тестировании связи выяснилось, что в 32-битной 1С провайдер работает успешно, а при выполнении регламентного задания на сервере 1С x64 возникает ошибка инициализации поставщика данных, вам необходимо установить 64-битную версию компонента Microsoft Access Database Engine.
Однако здесь системные администраторы часто сталкиваются с защитным поведением инсталляторов Microsoft: если на сервере уже установлен 32-битный пакет Microsoft Office, то установщик 64-битного ACE OLE DB заблокирует инсталляцию, выдав ошибку несовместимости.
Чтобы обойти это искусственное ограничение и установить драйверы обеих разрядностей на один сервер, выполните установку через командную строку с ключом пассивного режима:
AccessDatabaseEngine_X64.exe).
C:\PathToFolder\AccessDatabaseEngine_X64.exe /passive
Ключ /passive заставляет программу установки пропустить проверку конфликтующих версий MS Office и корректно развернуть 64-битные библиотеки OLE DB в операционной системе.
Когда вы успешно подключились к базе данных, вы можете столкнуться со следующей проблемой при попытке создать объект для выполнения параметризованных запросов:
Command = Новый COMОбъект("ADODB.Command");
Платформа возвращает ошибку: «Произошла исключительная ситуация (0x80040154): Класс не зарегистрирован».
Проанализируем причину. В операционных системах Windows Server 2008 R2 и Windows 7 после установки некоторых обновлений (в частности, связанных с пакетами обновления SP1) ломается совместимость интерфейсов ADO (ActiveX Data Objects). Microsoft изменила уникальные GUID идентификаторы классов ADO в системном реестре (подробнее проблема описана в статье базы знаний Microsoft KB2517589).
Для исправления этой проблемы необходимо вручную перерегистрировать ключевую библиотеку ADO (msado15.dll) в реестре операционной системы. Крайне важно сделать это с учетом разрядности вашего приложения 1С.
Если ваш код 1С выполняется в 32-битном процессе (файловая база, 32-битный клиент):
SysWOW64:
C:\Windows\SysWOW64\regsvr32.exe "C:\Program Files (x86)\Common Files\System\ado\msado15.dll"
Если ваш код выполняется в 64-битном процессе (на стороне 64-битного сервера приложений 1С):
System32:
C:\Windows\System32\regsvr32.exe "C:\Program Files\Common Files\System\ado\msado15.dll"
После успешной регистрации библиотеки в системном реестре вы увидите подтверждающее окно утилиты regsvr32, и создание COM-объекта ADODB.Command в коде 1С заработает в штатном режиме.
Рассмотрим более изящное и стабильное программистское решение. В среде 1С для извлечения данных из СУБД Access вовсе не обязательно создавать объект ADODB.Command. От этого класса можно полностью отказаться, что сделает ваш код более отказоустойчивым и независимым от тонкостей обновления операционных систем.
Разберем два эффективных альтернативных метода получения данных.
Метод 1: Прямое выполнение запроса через объект ADODB.Connection
Сам объект открытого соединения умеет выполнять SQL-запросы напрямую через свой метод Execute(). Данный метод сразу возвращает готовый объект набора записей (Recordset).
Посмотрим на практический пример реализации этого метода:
ФайлБазы = "C:\Database\sprut.mdb";
СтрокаПодключения = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ФайлБазы + ";Persist Security Info=False;";
Connection = Новый COMОбъект("ADODB.Connection");
Попытка
Connection.Open(СтрокаПодключения);
Исключение
ВызватьИсключение "Не удалось установить связь с СУБД Access. Описание ошибки: " + ОписаниеОшибки();
КонецПопытки;
// Текст запроса к таблице Access
ТекстЗапроса = "SELECT Kod, Name, Quantity FROM Goods WHERE Quantity > 0";
Попытка
// Выполняем запрос напрямую через объект соединения
RecordSet = Connection.Execute(ТекстЗапроса);
Исключение
Connection.Close();
ВызватьИсключение "Ошибка выполнения SQL-запроса: " + ОписаниеОшибки();
КонецПопытки;
// Обрабатываем полученные записи в цикле
Пока НЕ RecordSet.EOF Цикл
ТоварКод = RecordSet.Fields("Kod").Value;
ТоварИмя = RecordSet.Fields("Name").Value;
ТоварКол = RecordSet.Fields("Quantity").Value;
Сообщить(Шаблон("Код: %1, Название: %2, Остаток: %3", ТоварКод, ТоварИмя, ТоварКол));
// Переходим к следующей строке выборки
RecordSet.MoveNext();
// Предотвращаем зависание интерфейса при больших объемах данных
ОбработкаПрерыванияПользователя();
КонецЦикла;
// Закрываем ресурсы
RecordSet.Close();
Connection.Close();
Метод 2: Использование объекта Recordset с передачей активного соединения
Второй способ заключается в явном создании объекта ADODB.Recordset. Мы можем открыть его, передав SQL-запрос и уже открытый объект соединения Connection в качестве параметров метода Open().
Проанализируем этот программный код:
ФайлБазы = "C:\Database\sprut.mdb";
СтрокаПодключения = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ФайлБазы + ";";
Connection = Новый COMОбъект("ADODB.Connection");
Попытка
Connection.Open(СтрокаПодключения);
Исключение
ВызватьИсключение "Ошибка открытия базы данных Access: " + ОписаниеОшибки();
КонецПопытки;
// Создаем объект набора записей
RecordSet = Новый COMОбъект("ADODB.Recordset");
ТекстЗапроса = "SELECT * FROM Users";
Попытка
// Параметры метода Open:
// 1. Текст SQL-запроса или имя таблицы
// 2. Объект активного соединения Connection
// 3. CursorType (1 - adOpenKeyset, позволяет перемещаться по записям вперед и назад)
// 4. LockType (3 - adLockOptimistic, оптимистичная блокировка данных)
RecordSet.Open(ТекстЗапроса, Connection, 1, 3);
Исключение
Connection.Close();
ВызватьИсключение "Не удалось открыть таблицу: " + ОписаниеОшибки();
КонецПопытки;
Пока НЕ RecordSet.EOF Цикл
ИмяПользователя = RecordSet.Fields("UserName").Value;
Сообщить("Пользователь из базы Access: " + ИмяПользователя);
RecordSet.MoveNext();
ОбработкаПрерыванияПользователя();
КонецЦикла;
RecordSet.Close();
Connection.Close();
Оба представленных программных решения полностью исключают использование нестабильного класса ADODB.Command. Они работают напрямую с провайдерами OLE DB, обеспечивая высокую скорость чтения данных и обратную совместимость с любыми версиями операционных систем Windows.