ADO и COM или SQL-сервер своими руками
Оформил: DeeCo
Автор: Дмитрий Черненко
При всей нашей тяге к новому, всегда есть
объективные причины упорно противостоящие этому. Несмотря на настойчивое
продвижение в массовое сознание клиент - серверных технологий всегда остается,
какой то процент старых файловых баз данных с интерфейсами, написанными на
языках типа Clipper или FoxPro и данными, хранящимися в dbf - файлах.
Представьте такую картину. Многопользовательская
база данных. Информация хранится в dbf- файлах на машине называемой "сервер".
Вся обработка данных выполняется интерфейсной программой написанной в Clipper
и работающей на рабочих станциях. Железо рабочих станций старое и обработка
данных идет крайне медленно. На это ещё накладывается скорость обмена данными
по сети. В общем, картина не радостная.
Самым логичным решением проблемы является перевод
системы на клиент - серверную технологию. Но как поменять колеса на движущемся
автомобиле? Разработка серверной СУБД, клиентского приложения и перенос данных
на сервер самое логичное решение данной проблемы. Но рассмотрим такую
ситуацию, когда разработка серверной СУБД и клиентского приложения завершена,
данные перенесены на сервер и работа началась (так называемая опытная
эксплуатация). А когда все исходные данные внесены, расчеты выполнены, на
самом последнем этапе выплывает ошибка. Сроки выполнения работ могут быть
сорваны, а исправит ситуацию можно только двумя путями: либо повторить ввод
данных в старой системе, либо найти ошибку в бизнес - логике новой системы
(даже не знаю что быстрее).
Путь решения проблемы виден только один. Отладить
бизнес - логику на старой базе данных, а только потом перенести её и данные на
новый сервер. Для эмуляции работы SQL- сервера разработаем сервер приложений с
заложенной в него бизнес - логикой, который будет промежуточным звеном между
новым интерфейсом и старой базой данных. В классической литературе такую
трехзвенную систему называют ещё системой с "тонким" клиентом не входящим в
состав СУБД, которой у нас к тому же ещё нет. Это можно отнести к достоинствам
проекта. Что касается недостатков, то главным является "двойная" работа,
связанная с разработкой сервера СУБД сначала в виде "тонкого" клиента, а уже
потом переноса его на настоящую серверную платформу. Но в данном случае мера
эта вынужденная. Тут лучше "перебдеть" чем "недобдеть".
Перейдем от слов к делу. Система будет состоять
из трех компонентов: клиентской части, сервера приложений, эмулирующего работу
сервера СУБД при обращении к dbf- файлам и данных хранящихся в dbf-файлах.
Разработку серверной части проекта будем вести в Delphi. Создание сервера
приложений, как и любого другого проекта в Delphi начинается с создания
главной формы. Необходимости в ней, конечно, никакой, но поскольку всякое
Win-приложение без главной формы существовать не может, то можно сделать её
невидимой, установив соответствующее свойство главной формы после запуска
командой Form1.Visible:=False.
Если вы всё же решили оставить форму видимой, то
в этом случае можно приспособить её для отображения какой либо информации.
Во-первых, само открытое на экране окно будет свидетельствовать о том, что
сервер запущен. А для того чтобы окно сервера не было закрыто другими окнами
на экране, стоит установить свойство главной формы FormStyle равным
fsStayOnTop. При этом окно сервера всегда будет находиться всегда поверх
других открытых окон. А чтобы оно не мешало работе других приложений сделать
его как можно меньше и задвинуть в угол экрана. Ещё одна функция окна сервера
- индикация числа подключенных к серверу клиентов. Об этом мы поговорим чуть
позже. Можно так же включить в окно сервера различные настройки или вывод
информации о полученных запросах и статистике переданной информации и т.д. В
общем, совершенству нет предела.
Теперь стоит сохранить полученный проект в
отдельном каталоге. При первом сохранении будет выдан запрос об именах
модулей. С большинством имен задаваемых Delphi по умолчанию можно согласиться,
но имя проекта (файл с расширением dpr) стоит изменить с Project1 на ServApp.
Это следует сделать, для того чтобы в дальнейшем исполняемые exe- файлы имели
свое собственное имя ServApp.exe, а не безликое Project1.exe. Это нужно ещё и
для того чтобы в созданном чуть позже клиентском приложении ссылаться именно
на это имя сервера.
Хотя полученный при запуске проект открывает
полноценное Win- окно, он не несет никакой функциональности как сервер
приложений. Для построения полноценного сервера приложений вначале организуем
доступ к данным. Обычно для доступа к данным в Delphi используется механизм
BDE. Большая часть литературы, описывающая принципы работы с базами данных в
Delphi использует именно этот механизм. Но при работе с dbf-файлами имеет
смысл использовать более легковесный механизм ADO по сравнению с громоздким
BDE.
Для установки средств ADO на компьютер, где будет
работать сервер, необходимо всего лишь запустить файл Mdac_typ.exe (6358 KB)
обычно содержащегося в комплекте Delphi и нажать кнопку Install all Data
Access components (рис.1)
Рис.1 Окно установки средств MDAC 2.1
Для установки соединения с хранилищем данных (в
нашем случае каталог, содержащий dbf- файлы) будем использовать компонент
TADOConnection (страница компонентов ADO). Расположим этот не
визуальный элемент на форме как показано на рис. 5 и нажимаем кнопку в строке
свойства ConnectionString. На экране появится его окно редактора
свойств (рис.2)
Рис.2 Окно редактора свойств ConnectionString
Для создания строки соединения установим
переключатель в положение Use Connection String (Использовать строку
соединения) и нажмем кнопку Build… Будет открыто окно Data Link
Properties (Свойства связи с данными) где на вкладке Provider
выбираем драйвер для связи с данными. Так как наша цель доступ к dbf-файлам то
выбираем Microsoft OLE DB Provider for ODBC Driver (рис.3) и нажимаем
кнопку Next>>.
Рис.3 Вкладка Provider диалогового окна Data Link Properties
Перейдя на вкладку Connection настроим
драйвер для подключения к dbf- файлам. В 1й части определяем Use data
source name (Имя источника используемых данных) Из раскрывающегося списка
выбираем dBASE Files. 2ю часть вкладки пропускаем, поскольку dbf- файлы
не защищены паролем. В 3й части в строке Enter initial catalog to use
(Ведите исходный используемый каталог) вводим имя каталога содержащего нужные
нам dbf- файлы (рис.4).
Рис.4 Вкладка Connection диалогового окна Data Link
Properties
Для контроля правильности соединения щелкните по
кнопке Test Connection (Проверка соединения). В случае корректного
соединения будет выдано сообщение Test connection succeeded (Проверка
соединения прошла успешно). Другие свойства соединения на вкладках
Advanced (Дополнительные) и All (Все) оставим, как есть.
Нажимаем кнопку Ok. Результат нашей работы можно видеть на рис.5.
Рис.5 Главное окно сервера с компонентом TADOConnection и окно
его свойств
В значении свойства ConnectionString виден
текст строки соединения в виде набора следующих
установок: Provider=MSDASQL.1;Persist Security Info=False;Data Source=dBASE
Files;Initial Catalog=C:\Abonent\DBFPROM2
Для корректной работы компонента
TADOConnection с dbf- файлами имеет смысл так же изменить свойства
KeepConnection и LoginPromt на False для того чтобы при
соединении на экране не появлялось окно ввода пароля. Значение свойства
Connected так же установим False.
Теперь, когда соединение установлено, необходимо
решить проблему доступа к данным клиентского приложения. Для этой цели удобно
использовать COM/DCOM- ориентированную технологию, полная поддержкам которой
является одним из достоинств Delphi. Из репозитария объектов (команда
File/New, вкладка Multitier) выбираем объект Remote Data Module
(рис.6).
Рис.6 Объект Remote Data Module в окне репозитария
Объекты, помещенные в этот модуль, могут иметь COM-
интерфейс. Создание Remote Data Module начинается с вывода на экран
окна Remote Data Wizard в котором определяются 3 параметра.
- CoClass Name - имя класс, под которым данный сервер приложений
будет зарегистрирован в реестре (в нашем примере SrvApp).
- Instancing (способ создания экземпляров)- раскрывающийся список с
3я допустимыми вариантами. Этот параметр определяет, сколько копий
серверного процесса будет запущено:
- Internal -использование COM-сервера только внутри приложений
без доступа к внешних объектов;
- Single Instance (единственный экземпляр)- каждый клиент при
подключении создает свой отдельный экземпляр COM-сервера. Данный метод
позволяет получить параллельный доступ клиентов к данным, но создает
большую нагрузку на компьютер сервера;
- Multiple Instance (множественные экземпляры)- всеми клиентами
используется один экземпляр COM-сервера. Работа клиентов в данном случае
будет вестись по очереди, но нагрузка на сервер будет меньше. Для нашего
примера этот вариант наиболее предпочтителен.
- Treading Model (выбор модели потока)- этот параметр позволяет
подпрограммам поддержки COM распределять соединения по отдельным потокам без
необходимости применять дополнительный код. Для RDM модулей допустимы 4
модели потоков:
- Single (одиночная) - эта модель позволяет одновременно
обрабатывать только один запрос, но при этом нет необходимости заботится
об управлении потоками.
- Apartment (раздельная) - эта модель в сочетании с параметром
Multiple Instance дает самые высокие результаты. Все клиенты
использовать один процесс сервера и не будут блокировать работу друг
друга, поскольку каждый будет использовать собственный поток сервера.
Именно эту модель стоит выбрать при работе с BDE.
- Free (свободная) - эта модель обеспечивает ещё большую
гибкость, позволяя передавать серверу несколько запросов клиентов. Эту
модель выгодно использовать при работе с ADO.
- Both (обе модели) - эта модель также эффективна, как и модель
Free, но при её использовании обеспечивается автоматическая
сериализация обратных вызовов.
Для нашего примера выбираем
модель Free. Результат настроек COM-объекта показан на рис.7.
Рис.7 Окно создания RDM модуля
После нажатия кнопки Ok будет создана
новая библиотека типов для проекта (файл ServApp.tlb) содержащая описание
интерфейса и COM- класса. Так же будет сгенерирован новый модуль в проекте
(файл Unit2.pas). В созданный удаленный модуль поместим компонент
TADOQuery (страница компонентов ADO) связанный с источником данных с
помощью компонента TADOConnection. Для этого свойство компонента
TADOConnection. Connection зададим равным
Form1.ADOConnection1. Не забудьте при этом в модуль Unit2
включить ссылку на модуль формы Form1 uses Unit1; иначе компонент TADOConnection останется
невидимым для TADOQuery.
Добавим, также компонент TDataSetProvider
(страница компонентов Midas), и значение его свойства DataSet выберем
имя компонента TADOQuery, а его свойство
Options.poAllowCommandText зададим значением True. Теперь доступ
к данным, возвращаемым в результате выполнения запроса компонентом
TADOQuery, другими приложениями будет осуществляться через COM-
интерфейс.
Теперь вернемся к индикации числа подключенных к
серверу клиентов. Для этого расположим на форме компонент TLabel и его
свойству Caption зададим значение "0". Кроме того, опишем процедуру изменения
значения счетчика. Переменная FCount содержит число подключенных к серверу
клиентов. Процедура UpdateCount изменяет значение счетчика подключений.
type
TForm1 = class(TForm)
Label1: TLabel;
private
{ Private declarations }
FCount: Integer;
public
{ Public declarations }
procedure UpdateCount(FCon: bool);
end;
{При установке соединения в процедуру передается значение True, при
отключении False}
procedure TForm1.UpdateCount(FCon: Bool);
begin
if FCon then
Inc(FCount)
else
Dec(FCount);
Label1.Caption := intToStr(FCount);
end;
{Для того чтобы значения счетчика изменялост описанную процедуру
необходимо поместить в события модуля RDM Create и Destroy соответственно}
procedure TSrvApp.RemoteDataModuleCreate(Sender: TObject);
begin
Form1.UpdateCount(True);
end;
procedure TSrvApp.RemoteDataModuleDestroy(Sender: TObject);
begin
Form1.UpdateCount(False);
end;
На этом создание простого сервера приложений
будем считать завершенным. Сохраним проект и скомпилируем приложение. Очень
важно не забыть зарегистрировать сервер приложений в реестре компьютера, где
он будет использоваться. Для этого необходимо запустить приложение сервера с
ключом /regserver. Для обратной операции очистки реестра используется ключ
/unregserver.
Создание клиентского приложения начнем с того,
что определимся, какие из протоколов вызова сервера приложений и соединения с
ним клиента лучше использовать. Delphi поддерживает четыре протокола
организации распределенных вычислений. Это DCOM, Sockets, WebConnection, и
CORBA. Для данного примера возьмем два из них. DCOM так как он наиболее
адаптирован к Windows и Sockets так как он является самым простым. Разница в
работе с ними будет отличаться в настройке соединения с сервером и ещё для
технологии Sockets необходимо на сервере запустить менеджер подключений
(ScktSrvr.exe - каталог Delphi\Bin, 520 KB).
Начнем. Создадим новый проект File/New
Application. Разместим в окне проекта элемент TRadioGroup с двумя
вариантами DCom и Socet для выбора технологии подключения к серверу, два
элемента TEdit для установки имени компьютера или его IP адреса и два
элемента TButton (страница компонентов Standard) для подключения к
серверу и отключения от него. Четыре не визуальных компонента
TDCOMConnection, TSocketConnection, TClientDataSet,
(страница компонентов Midas), TDataSource (страница компонентов Data
Access) для доступа к данным. А так же три визуальных компонента для
управления TDBNavigator, и отображения TDBGrid данных (страница
компонентов Data Access) и строку ввода запроса TEdit. Результаты нашей
работы приведены на рис 8.
Рис 8. Окно проекта клиента в редакторе
Теперь компонентам TDComConnection и
TSourceConnection зададим в качестве свойства ServerName имя
нашего сервера приложений ServApp.SrvApp. Вот где нам пригодилось имя
сервера заданное при сохранении проекта, а так же имя класса, под которым
сервер будет зарегистрирован в реестре. Так же надо следить, чтобы для этих
компонентов их свойства LoginPrompt были установлены False,
чтобы без нужды не выскакивало окно ввода пароля.
Для компонента TClientDataSet установим
свойство ProviderName в значение DataSetProvider1.
Для соединения компонент TDataSourece с
компонентом TClientDataSet путем выбора его из списка в свойстве
DataSet.
Так же подключим компоненты TDBGrid и
TDBNavigator к компоненту TDataSource путем выбора его из списка
в свойствах DataSource.
Далее научим нашего клиента соединяться с
сервером. Для этого наполним содержанием событие кнопки "Connect".
procedure TForm1.Button1Click(Sender: TObject);
begin
{выбор технологии соединения}
case RadioGroup1.ItemIndex of
0:
begin // технология DCOM
DCOMConnection1.ComputerName := Edit2.Text;
//Заносим имя компьютера, где установлен сервер
ClientDataSet1.RemoteServer := DCOMConnection1;
//Связываем набор данных с компонентом DCOM
DCOMConnection1.Open; //Выполняем соединение с сервером
end;
1:
begin // технология Socket
SocketConnection1.Address := Edit1.Text;
// Заносим IP адрес компьютера, где установлен сервер
SocketConnection1.Host := Edit2.Text;
// Заносим имя компьютера, где установлен сервер
ClientDataSet1.RemoteServer := SocketConnection1;
//Связываем набор данных с компонентом Socket
SocketConnection1.Open; //Выполняем соединение с сервером
end;
end;
end;
Соединение с сервером мы выполнить можем, но
выбор данных не происходит, так как компонент сервера TADOQuery не
содержит SQL запроса. Для выборки данных и чтобы не плодить лишних кнопок
опишем событие строки ввода SQL-запроса на нажатие клавиши.
procedure TForm1.Edit3KeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then // Если нажат "Enter" то выполняем запрос.
begin
ClientDataSet1.Close; // Закрыть набор данных
ClientDataSet1.CommandText := Edit3.Text;
//Передать серверу текст SQL-запроса
ClientDataSet1.Open; // Открыть набор данных и выполнить SQL-запрос
end;
end;
//Для разъединения с сервером опишем событие кнопки "Disconnect".
procedure TForm1.Button2Click(Sender: TObject);
begin
DCOMConnection1.Close; //Закрыть соединение DCOM
SocketConnection1.Close; //Закрыть соединение Socket
ClientDataSet1.Close; //Закрыть набор данных
end;
Теперь запускаем нашего клиента, выбираем
технологию подключения, вводим имя компьютера и/или IP адрес, если будет
использоваться технология Sockets, и нажимаем кнопку "Connect". При этом на
компьютере сервера будет запущено серверное приложение, и счетчик подключений
покажет единицу. Далее в строке SQL-запроса вводим команду, например "Select *
from 1_prom" и нажимаем "Enter". После небольшой паузы в grid-таблице увидим
результаты выполнения запроса. При нажатии кнопки "Disconnect" произойдет
разъединения с сервером, и если оно было единственным, то сервер будет
выгружен из памяти.
И в заключении ещё раз хочу напомнить что для
использования технологии DCOM нам не нужно никаких дополнительных драйверов.
Windows 98 имеет в своем наборе всё, что нужно. А вот для технологии Socket
необходимо предварительно запустить на сервере менеджер подключений клиентов
(ScktSrvr.exe). И ещё. Надеюсь, вы понимаете, что это только начало и создание
серьезной программы "за 21 день" не научишься. Если так, то дерзайте.
|