Часть
II.
Программирование
баз данных
Мощь базы
данных реализуется через инструменты, предназначенные для работы с ней. В этой
части мы поговорим о том, как создавать такие инструменты, используя некоторые
популярные сегодня языки программирования. На примере создания веб-приложений
для бизнеса мы обсудим API и инструменты, необходимые для максимального использования
потенциала MySQL и mSQL. Эта часть начинается с нескольких обзорных глав по
архитектуре приложений для работы с базами данных и СGI-программированию. Однако
основное содержание этой части посвящено программированию на различных языках
для MySQL и mSQL.
Архитектуры
приложений для
работы с базами данных
Прежде чем
разбираться в деталях разработки приложений для работы с базами данных на различных
языках, следует потратить некоторое время и шире взглянуть на проектирование
этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру
клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны
для программирования MySQL и mSQL, но не являются специфичными только для этих
СУБД. Напротив, они применимы в любой среде программирования баз данных. Если
не учитывать принципов архитектуры, то может оказаться, что ваши приложения
не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся
обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких
сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между
объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.
В упрощенном
виде архитектура клиент/сервер предполагает разделение происходящей в приложении
обработки на две или более логически различные части. До сих пор в этой книге
мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве.
Однако они выполняют свое предназначение только тогда, когда используются какими-либо
приложениями. Упрощая, можно сказать, Что база данных составляет одну часть
архитектуры клиент/сервер. База данных является «сервером», а всякое
использующее ее приложение
является «клиентом». Часто клиент и сервер расположены на разных
машинах; в большинстве случаев приложение клиента является дружественным интерфейсом
к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.
Возможно,
вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к
определенной задаче приложений клиент/сервер для Интернет на протяжении всей
книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в
котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии
сервер является не сервером реляционных баз данных, а специализированным файл-сервером.
Важнейшим свойством сервера является то, что он предоставляет данные клиенту
в определенном формате.
Рис. 8-1.
Архитектура клиент/сервер
При создании
приложения для работы с базой данных прежде всего необходимо иметь возможность
связать клиента с базой данных. Поставщики баз данных предпочитают скрывать
от разработчиков основополагающие механизмы связи посредством API, ориентированных
на конкретный язык. Когда вы создаете приложение для работы с базой данных,
то используете специальные библиотеки, которые транслируют ваши запросы в пакеты
TCP/IP, передающиеся по сети к серверу базы данных.
Внешний вид
этих API для доступа к базам данных различен и зависит от языка программирования,
а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно
разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете
в этой книге, различия минимальны.
В части I
«Введение в MySQL и mSQL» мы дали понятия управления транзакциями
и результирующего набора. Приложение для работы с базой данных — всего лишь
инструмент для управления транзакциями и обработки результирующих наборов. Например,
если ваше приложение
является адресной книгой, то обработка результирующих наборов заключается в
том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление
транзакциями просто сводится к тому, чтобы изменения в таблицах address и person
производились как единое целое.
Мы
уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение
в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение
заставляет принимать специальные меры для того, чтобы целостность данных не
нарушалась в результате отказа, происходящего в промежутке между двумя связанными
между собой обращениями к базе данных.
Два других
важных момента в работе приложения - это подключение и отключение. Вполне понятно,
что перед тем, как выполнить запрос, необходимо подключиться к базе данных.
Однако довольно часто забывают о второй стороне медали- необходимости «убрать
за собой». Следует всегда освобождать все захваченные ресурсы базы данных,
когда они вам больше не нужны. В долго живущих приложениях, таких как демон
Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы
данных, и, в конце концов, заблокирует систему.
«Уборка
за собой» включает в себя правильную обработку ошибок. Хорошие языки программирования
затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся
ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того,
какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут
возникать при данном вызове API, и в каждой исключительной ситуации действовать
надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении
базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют
непосредственно обращаться с данными в том виде, в каком они в принципе существуют
в базе данных. Глава 13 «С и C++», раскрывает практические
детали программирования в этой модели с использованием С API для MySQL и mSQL.
Доступ к
реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс:
реляционный мир занимается исключительно манипуляциями с данными, в то время
как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем
поведения. В объектно-ориентированном приложении база данных служит средством
сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование
рассматривает данные запроса не как набор строк, а как собрание объектов.
Объектное/реляционное
моделирование
Основная
проблема, которая встает перед разработчиком объектно-ориентированного приложения
при использовании реляционной базы данных, это - как отобразить реляционные
данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта
в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.
Практические
правила для объектно-реляционного моделирования
|
Вспомните
адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address
и person, как на рис. 8-2.
Рис. 8-2.
Модель данных простого приложения адресной книги
Есть
весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача
объектно-ориентированного подхода к реляционным данным - это, получив эти данные,
немедленно создать экземпляр объекта. Приложение должно работать с данными только
через объекты. Большинство традиционных методов программирования, включая разработку
на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы
данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном
программировании баз данных вы имеете дело с объектами, а не данными.
Рис. 8-3
показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая
строка базы данных преобразуется в программный объект. Таким образом, ваше приложение
принимает результирующий набор и для каждой возвращаемой строки создает новый
экземпляр Address или Person. Труднее всего справиться с проблемой, о которой
уже говорилось: как в приложении установить связь между человеком и его адресом?
Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому
человеку, но сохранить объект Address внутри таблицы person реляционной базы
нельзя. Модель данных предполагает хранение связей между объектами с помощью
внешних ключей, для чего в таблицу person заносится address_id.
Рис. 8-3.
Объектная модель, поддерживающая простое приложение адресной книги
Самое незначительное
усложнение объектной модели может вызвать бездну проблем при установлении соответствия
наших объектов и модели данных. Допустим, что Person является потомком Entity
и класс Company тоже является потомком Entity. Как отделить Entity от Person
или Company? Приведенное выше правило фактически является скорее рекомендацией.
В некоторых случаях базовый класс является чисто абстрактным и, следовательно,
не имеет в базе связанных с ним данных. В таком случае для этого класса в базе
данных не будет объекта.
До сих пор
мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями
- клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста
и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного
программирования. Первая проблема недавно нашла отражение в дискуссиях относительно
«тонких клиентов». Потребность в тонких клиентах происходит из беспокоящей
тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась
в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные
из базы в GUI, а затем все операции над этими данными проводят в GUI.
Такая тесная
привязка интерфейса пользователя к ядру базы данных приводит к появлению программ,
которые трудно модифицировать и невозможно масштабировать при увеличении числа
пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя,
то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза
пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить
для GUI только одну задачу- действовать в качестве интерфейса пользователя.
Такой интерфейс пользователя действительно является тонким клиентом.
Влияние на
масштабируемость сказывается и с другой стороны. Когда требуется переработать
приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом
данных, модификация может быть осуществлена в результате изменений, вносимых
в базу данных, в том числе таких, которые состоят в распределении базы данных
по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится
делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных
исключительно с сервером.
Тонкие клиенты
- не единственное сегодняшнее поветрие. Другая тенденция - повторное использование
кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой
деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя,
то добиться повторного использования кода будет, по меньшей мере, трудно. Решением
этих проблем является разбиение приложения на три, а не на две части. Такая
архитектура называется трехзвенной.
Когда
мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое
различие. Разновидностью тонкого клиента, иногда называемой «сверхтонким
клиентом», является то, что обычно всеми воспринимается как Web-страница.
Web-страница может динамически создаваться на Web-сервере. В этом случае большая
часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.
Сравните
двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на
рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой
данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения
- деловую логику, которая является общей для некоторой области задач. Клиент
становится ничем иным, как средством просмотра объектов среднего яруса, а база
данных становится хранилищем этих объектов.
Самое главное,
что вы выигрываете, - это разделение интерфейса пользователя и базы данных.
Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения
о том, как работать с базой данных, могут размещаться в среднем ярусе.
Две главные
задачи сервера приложений - это изоляция подключений к базе данных и обеспечение
централизованного хранилища для деловой логики. Интерфейс пользователя имеет
дело только с отображением и вводом данных, а ядро базы данных занимается только
проблемами базы данных. При перемещении обработки данных в центральное место
одну и ту же программу сервера приложений могут использовать различные интерфейсы
пользователя, и устраняется необходимость писать правила обработки данных всякий
раз, когда вы создаете новое приложение.
Рис. 8-4. Трехзвенная архитектура