Давно тому назад я рассказывал на страницах "Компьютерных вестей" о технологиях доступа к данным, предлагаемых программистам и пользователям корпорацией Microsoft. Но общих сведений для работы с конкретной технологией не хватит даже самому талантливому программисту, а потому я решил рассказать подробнее о той из них, которая лучше всего себя зарекомендовала, так сказать, на поле боя. И для начала напомню, что же такое, собственно говоря, ODBC.
Четыре буквы, что за ними?
ODBC расшифровывается как Open Database Connectivity. На русский язык это словосочетание традиционно переводится как "открытый интерфейс взаимодействия с базой данных". Фактически, это программные интерфейсы, которые обеспечивают универсальное для всех СУБД взаимодействие между ними и пользовательским приложением. ODBC - программный интерфейс (API - Application Programming Interface), независимый от языка программирования и даже операционной системы. В общем-то, это всё действительно так, поскольку доступ к библиотекам, реализующим ODBC, например, под Windows, можно осуществлять и на Delphi, и на C++, и вообще практически на чём угодно. Есть даже реализация ODBC под UNIX-подобные платформы - UnixODBC.
Интересно, что хотя сейчас многие связывают возникновение ODBC с корпорацией Microsoft, это не совсем так. Изначально технологию разработала компания X/Open. Сейчас ODBC API - международный стандарт, который основан на спецификациях CLI от X/Open и ISO/IEC.
Каким образом реализуется поддержка множества СУБД, весьма, порой, разных по своему внутреннему устройству и "родному" интерфейсу доступа? Идея, как и всё гениальное, проста: для этого используется промежуточная прослойка в виде программы-посредника, которая транслирует запросы приложения системе управления базами данных. Такая программа называется ODBC-драйвером. Для каждой СУБД нужен свой драйвер, но программисту, если он нашёл себе нужный, должно быть всё равно, кто и когда его сделал и как при этом мучился - с его точки зрения, интерфейс всех ODBC-драйверов одинаков. Хотя, в общем-то, ODBC - технология гибкая, поэтому вовсе не все возможности в данном конкретном драйвере могут быть реализованы.
Для работы с данными приложение использует структурированный язык запросов - Structured Query Language, или, сокращённо, SQL. Такова спецификация ODBC API, и именно в этом состоит секрет её популярности. SQL - самый удобный из придуманных на сегодняшний день способов манипуляции данными. Если диалект, который использует СУБД, отличается от стандартного SQL, то драйвер преобразует запрос "на лету", и программисту не придётся вникать в тонкости запросов для каждой новой версии каждой СУБД.
Драйверы могут поддерживать три уровня грамматики SQL. Минимальная грамматика поддерживается всеми драйверами - это запросы Create Table, Drop Dtable Select, Insert, Update Dearch, Delete, Search; типы данных Char,VarChar или Long VarChar. Основная грамматика состоит из минимальной и запросов Alter Table, Create Index, Drop Index, Create View, Drop View, Grant, Revoke Select, а также типов данных Decimal, Numeric, SmallInt, Integer, Real, Float, Double Precision. Третий уровень грамматики - расширенная. Это основная плюс внешние соединения, типы Bit, TinyInt, BigInt, Binary, VarVariant, Long, VarBinary, Date, Time, TimeStamp, а также пакетные операторы SQL и вызов хранимых процедур.
Помимо задачи унификации доступа к данным, ODBC попутно решает ещё одну: одновременный доступ к нескольким базам данных. Для этого, помимо самих драйверов, в архитектуре ODBC предусмотрен специальный менеджер драйверов (Driver Manager), который по-русски также называют администратором или диспетчером драйверов. Он позволяет вызывать функции драйверов из прикладного приложения таким образом, что сохраняется возможность одинаково работать с разными СУБД и при этом не волноваться по поводу таблицы указателей на функции. Общую схему архитектуры ODBC можно увидеть на иллюстрации к статье.
Практика
Конечно, найти информацию по использованию ODBC легко - например, её полно в MSDN Library. Но эта статья задумывалась как нечто, имеющее практическую пользу, поэтому, думаю, будет совсем не лишним рассказать о практических основах работы с ODBC.
Поскольку ODBC для Windows реализована корпорацией Microsoft, она включила поддержку этой технологии в свои библиотеки для разработчиков. Поэтому сейчас мы с вами воспользуемся библиотекой MFC, которая, мягко говоря, знакома всем разработчикам, имевшим дело с Visual C++. Хотя она инкапсулирует и не все функции ODBC API, её для большинства проектов будет вполне достаточно.
Для работы с ODBC понадобится включить в приложение заголовочный файл afxdb.h. Класс, который используется для работы с БД через ODBC и имеет название CDatabase. Установка соединения вызывается методом Open, который имеет великое множество параметров:
virtual BOOL Open(LPCTSTR lpszDSN, BOOL bExclusive = FALSE, BOOL bReadOnly = FALSE, LPCTSTR lpszConnect = "ODBC;", BOOL bUseCursorLib = TRUE); throw(CDBException, CMemoryException);
Однако большую их часть задавать зачастую не обязательно, поскольку значения по умолчанию подходят львиной доле всех ODBC-драйверов. Задать нужно самый главный параметр - первый, lpszDSN. Это строка, которая указывает имя используемого DSN. Сейчас нужно сделать небольшое отступление и объяснить, что скрывается за этими тремя английскими буквами.
В данном случае под DSN понимается вовсе не система доменных имён, которая имеет похожую аббревиатуру - DNS, а Data Source Name - имя источника данных. Фактически, DSN - это строка, по которой ODBC определяет местонахождение драйвера, его тип, а также дополнительные параметры, нужные для установки соединения. Использование строковых DSN намного удобнее, чем, например, могло бы быть использование их в виде чисел - думаю, это очевидно.
В принципе, источник данных можно и не указывать - тогда при попытке установления соединения у пользователя спросят, какой DSN использовать. И не факт, что он будет знать, как ответить на этот вопрос. Кроме того, если у вас многопользовательская база данных, то ODBC сама спросит у него логин и пароль. Но при желании можно и не перекладывать эту задачу на ODBC, а опрашивать пользователя самостоятельно, меняя параметр lpszConnect на строку вида ""ODBC;UID=ADMIN;PWD=123"", где, естественно, вместо "ADMIN" и "123" должны быть соответствующие имя пользователя и пароль.
Для того, чтобы определить, активно ли соединение с базой данных, нужно воспользоваться методом IsOpen всё того же класса CDatabase. Метод этот никаких параметров не имеет, а возвращает значение булевского типа. Для закрытия соединения используется точно метод Close, который также не имеет параметров.
Таким образом, минимальный код для работы с БД (в качестве источника данных возьмём, например, навевающий ностальгию Microsoft Access 97) будет иметь следующий вид:
cdbMyDB.Open("MS Access 97 Database"); cdbMyDB.Close();
В классе CDatabase есть метод, позволяющий узнать параметры уже установленного соединения. Называется он GetConnect, параметров не имеет и возвращает все параметры соединения в том же виде, в каком они устанавливаются методом Open (т.е. на выходе этого метода будем иметь строку вида "параметр1=значение1; параметр2=значение2; параметр3=значение3"). Аналогичным образом получается имя базы данных, с которой установил соединение драйвер, только для этого используется метод GetDatabaseName. Для проверки прав данного пользователя на внесение изменений в базу данных используется булевский метод CanUpdate.
Отдельно стоит упомянуть о транзакциях. Они, конечно же, в ODBC имеются, но только не все драйверы их могут поддерживать. Для того, чтобы узнать данную возможность конкретного драйвера, нужно воспользоваться методом CanTransact, который не имеет параметров и возвращает значение булевского типа. В случае, если драйвер признался, что транзакции он всё же поддерживает, то, чтобы их реализовать, перед внесением изменений в БД нужно вызывать метод BeginTrans, а после - CommitTrans для подтверждения транзакции, либо Rollback для её отмены. Все эти методы параметров не имеют и выдают после своей работы булевское значение, которое характеризует успешность их выполнения.
Обо всём мы с вами уже успели поговорить, кроме самого важного - то есть, непосредственной работы с данными. Для неё нам понадобится класс CRecordset, который и занимается выполнением SQL-запросов. При создании экземпляра этого класса конструктору в качестве параметра нужно передать экземпляр класса CDatabase. Далее для создания таблицы на основе SQL-запроса нужно воспользоваться методом Open.
Однако, углубившись в практику, я забыл, что хотел подробнее рассказать об одном аспекте, который уже упоминал выше.
UnixODBC
Глядя на примеры с MFC и на периодические упоминания корпорации Microsoft, можно и забыть о том, что ODBC - технология, вообще-то, кросс-платформенная. Вот потому и хочу я чуть подробнее рассказать о проекте UnixODBC.
Цель проекта unixODBC, по словам самих его участников, состоит в том, чтобы разрабатывать и поддерживать unixODBC - API, который призван стать стандартом для ODBC на не-Windows системах. Задача осложняется тем, что реализация ODBC для Windows содержит множество расширений, не предусмотренных стандартом, и их тоже нужно реализовывать. Наилучшие результаты пока что достигнуты в написании UnixODBC под Linux. Библиотеки unixODBC распространяются согласно лицензиям GPL и LGPL, и последняя лицензия для библиотек позволяет применять их в коммерческом программном обеспечении с закрытыми исходными текстами.
В настоящий момент, помимо непосредственно библиотек, в рамках проекта написана масса полезных для разработчика утилит и драйверов. Найти всё это можно по адресу www.unixodbc.org. Русскоязычная документация по UnixODBC в Интернете практически отсутствует, если не учитывать некоторое число обзорных статей. Но англоязычной документации много, и, кроме того, для программиста UnixODBC схож с ODBC для Windows. А вот администраторам, конечно, придётся покорпеть над английскими "мануалами".
Однако, если unixODBC очень похожа на ODBC из Windows, то другая технология, очень созвучная по названию той, которую мы с вами сейчас рассматриваем, внутри отличается кардинально.
JDBC - совсем не ODBC для Java!
Есть у компании Sun Microsystems торговая марка JDBC. Согласитесь, звучит похоже на ODBC. И есть соблазн считать JDBC реализацией ODBC для языка Java. Однако это совсем не так на самом-то деле. Хотя JDBC очень похожа на ODBC идейно, это совсем другая технология.
JDBC, как и ODBC, основана на концепции драйверов, позволяющих получать соединение с базой данных по специально описанному URL. Загрузившись, драйвер сам регистрирует себя и вызывается автоматически, когда программа требует URL, содержащий протокол, за который драйвер "отвечает". Соединение с базой данных описывается классом, реализующим интерфейс java.sql.Connection. Имея соединение с базой данных, можно создавать объекты типа Statement, служащие для исполнения запросов к базе данных на языке SQL.
Однако драйверы для ODBC в общем случае не подходят для JDBC, хотя есть и такие драйверы, которые совмещают в себе функции для обеих технологий.
Адепты Java говорят, что JDBC позволяет писать приложения быстрее, чем ODBC из-за того, что сам интерфейс объектно-ориентирован. Однако если использовать MFC и другие оо-библиотеки, то можно так же быстро писать приложения и на других языках программирования.
Напоследок
Кто-то может сказать, что ODBC, созданная ещё в 1991 году, уже устарела морально. Однако востребованность этой технологии опровергает все доводы её противников. До сих пор продолжают разрабатываться приложения, которые поддерживают работу с СУБД через ODBC. И их появляется гораздо больше, чем, скажем, для ADO.NET.
На мой взгляд, использовать в своих программах такой проверенный временем интерфейс доступа к данным вполне разумно. Объектно-ориентированные библиотеки-обёртки, которых для ODBC написано немало, делают скорость разработки совсем не маленькой. Так что изучайте ODBC, и удачи вам в этом не таком уж и простом деле.
Вадим СТАНКЕВИЧ,
[email protected]
Комментарии
Вроде бы те же задачи решает.