Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2006.02.26;
Скачать: [xml.tar.bz2];

Вниз

Интерфейс взаимодейстия с базой   Найти похожие ветки 

 
Piter ©   (2006-01-02 23:33) [0]

Нужна организовать для DLL-плагина к программе доступ к SQL-базе. База - Interbase, но это не так важно.

То есть, внутри программы понятно: TDatabase / TQuery - все ясно.

А вот как организовать интерфейс взаимодействия с плагином? Чтобы плагин мог выполнять SQL запросы и получать результаты? Может кто занимался подобным, имеет опыт?

Может что-то типа:

CreateRequest("SQL-выражение") - функция возвращает Handle некоего созданного объекта (ну там ноль в случае неудачи)

Потом всякие:

GetParam(Handle, "ParamName", AsInteger)

А в конце работы нужно закрыть объект:

CloseRequest(Handle);

Соответственно, в программе Handle это может быть чисто физически просто адрес TQuery. При выполнении запроса CreateRequest создается объект TQuery, Handle возвращается плагину. При CloseRequest объект TQuery уничтожается.

TQuery вроде как потоко-безопасный.

Покритикуйте плиз данную схему и как по другому можно?

В данной схеме меня пока смущает частое создание/уничтожение объекта TQuery - при каждом запросе. С другой стороны, вроде ничего страшного, TDataBase один общий будет, так что по скорости проблем особо не должно быть.


 
Piter ©   (2006-01-02 23:37) [1]

Ну а:

CreateRequest, GetParam, CloseRequest - соответственно, просто импортируемые плагином функции


 
Piter ©   (2006-01-02 23:40) [2]

Еще вот что смущает - GetParam же может возвращать разные типы: integer, float, string и т.д.

То есть, в общем случае он возвращает PByte какой-нибудь, а уж плагин должен разобраться на что это ссылка в соответствии с поданым запросом: AsInteger, AsString и т.д.

Или сделать отдельные функции:

GetIntegerParam(Handle, "ParamName")
GetStringParam(Handle, "ParamName")

и т.д.

Вот думаю - как лучше?


 
Sergey Masloff   (2006-01-02 23:43) [3]

Непонятно зачем это. Да и клиентская библиотека InterBase все рвно в очередь построит все запросы, непараллельная она.
 Плагины к разным базам обращаться будут чтоли?


 
Sergey Masloff   (2006-01-02 23:57) [4]

Можно заюзать MIDAS.
Например что-то в таком роде:
1 модуль реализующий IAppServer. Он реализует соединение с БД
   Можно сделать его универсальным то есть он будет получать SQL запрос в текстовом виде, создавать динамически TQuery и провайдера для него и отдавать ссылку на провайдер клиенту. А тот уже штатными средствами ClientDataSet будет работать с данными. Параметры можно передавать через OwnerData
 Можно сделать несколько стандартных интерфейсов - выполнение произвольного SQL выполнение ХП и так далее. Интерфейс наследник IAppServer публикуется и используется всеми другими плагинами дла работы с базой.
 Может конечно и изврат но может и нет. Я особо идею не обдумывал но реализовать так точно можно. И будет пусть и не тривиальное но использование довольно стандартной технологии.


 
Piter ©   (2006-01-03 01:12) [5]

Sergey Masloff   (02.01.06 23:43) [3]

ты не понял. Программа - плагиновая.

Плагин может делать в принципе что ему захочется. Он, конечно, вправе использовать сам какие ему угодно базы данных. НО - зачем?

Хочется с помощью ядра программы предоставить доступ к нормальной базе данных. Более того, вполне возможно, что работа с базой будет осуществляться еще одним плагином. Хочешь - плагин для Interbase, хочешь - плагин для Access или MS SQl, да хоть Oracle.

Для других плагинов все это абсолютно прозрачно. Пусть они просто оперируют простыми SQL выражениями и получают наборы данных. А откуда взяты эти данные - плагин и не знает. Да хоть IB, хоть Oracle, хоть из текстовых файлов.

Проблема не в распараллелизации и подобном. Проблема в описании интерфейса взаимодействия плагина с базой, хранилищем данных.

В Delphi это удобно сделано с помощью TQuery, например. Верно же? Это некая стандартизация доступа к данным. НО. У меня .NET пока не планируется, поэтому действовать на уровне объектов нельзя - плагин может быть написан и на Delphi, и на C++, на чем угодно, что может вызывать WinApi функции и компилировать библиотеки DLL.

То есть, в программе то наверняка будет TDataBase, TQuery, но как предоставить данные плагину? В этом и проблема...

Уф, надеюсь внятно объяснил... Если что - спрашивай.


 
Piter ©   (2006-01-03 01:17) [6]

Кстати, не исключая вариант, что это я тебя не понял, Сергей.

Тогда плиз поподробнее :)

Особенно про:

Sergey Masloff   (02.01.06 23:57) [4]
создавать динамически TQuery и провайдера для него и отдавать ссылку на провайдер клиенту


что значит отдавать ссылку на провайдера? Что это такое?
Что может извлечь плагин, имея ссылку на провайдера. Да и что такое провайдер? :)

P.S. Думаю, и так понятно, что в базах я ламачок :)


 
Piter ©   (2006-01-03 01:19) [7]

Piter ©   (03.01.06 1:12) [5]
В Delphi это удобно сделано с помощью TQuery


ну точнее, наверное, сказать TDataSet, но опять же не суть важно, думаю проблема понятна...


 
Sergey Masloff   (2006-01-03 08:29) [8]

Ну я же дал направление поиска - MIDAS. Все уже давно реализовано. Провайдер посредник между датасетом в серверном модуле (Query там или StoredProcedure) и датасетом в клиентском модуле.
 То есть схема работы такая:

 1) У тебя появляется интерфейс потомок IAppServer в котором тебе придется добавить методы принимающие строку например с текстом SQL и возвращающие провайдер к которому можно подключить ClientDataSet

 2) У тебя появляется плагин реализующий твой потомок IAppServer. ТО есть в нем появляется TREmoteDataModule и методы реализации твоего IAppServer. Базовое приложение (к которому подцепляются все плагины) будет использовать эту реализацию для предоставления ее остальным плагинам - клиентам.  Кстати меняя этот "серверный" плагин можно допустим коннектится действительно не к IB а к ораклу или еще куда

 3) Появляются плагины-клиенты. Им всем передается ссылка на IAppServer которую они дергают для заполнения данными своих TClientDataSet.

 Естественно все это работает только если клиентские плагины дельфийские или C++Builder овские.

 Так что вооружайся справкой и вперед. Ключевые слова multi-tiered database applications. Простейший пример MIDAS есть в каталоге DEMOS. Только там все рассчитано что клиент и сервер на разных машинах поэтому всякие доп. прослойки появляются тебе они не нужны. Просто нужно напрямую ссылки на IAppServer передавать а не парится со всякими SocketServer-ами наверное.

Если есть вопросы общего плана я ответить могу а вото подробности - врядли Delphi у меня нет проверить ничего не могу ;-)


 
Sergey Masloff   (2006-01-03 08:39) [9]

Сейчас в новых (D6 D7) MIDAS по-другому называется. DataSnap вроде.


 
Sergey Masloff   (2006-01-03 10:00) [10]

Еще можно, видимо, обмениваться ADO-шными рекордсетами но там больше придется писать в плане изменений данных. То есть не проблема заполнить рекордсет и отдать его клиенту а вот написать универсальный механизм записи результатов редактирования клиентом рекордсета в базу не так просто.
 Именно если это должен быть универсальный механизм сложно так-то ничего сложного


 
Desdechado ©   (2006-01-03 11:30) [11]

Обязательно при передаче хэндлов (если ты хочешь именно по-своему сделать) помни, что компилироваться твоя прога и плагины должны на ИДЕНТИЧНЫХ версиях, ибо описание класса хранится и в EXE, и в DLL. И может (при разных версиях) получиться так, что обращаясь (в EXE) к TQuery.SQL.Text из плагина ты, на самом деле, обратишься к какому-нить другому свойству, расположенному по этому адресу (из-за несоответствия описания таблицы классов).
Часто это выявляется далеконе сразу, ибо положение свойств классов меняется редко, но вполне возможно. И будешь ловить AV и долго гадать, в чем дело...


 
Piter ©   (2006-01-03 12:51) [12]

Sergey Masloff   (03.01.06 8:29) [8]
Естественно все это работает только если клиентские плагины дельфийские или C++Builder овские


так вот ничего естественного!

Сергей, я же писал:

Piter ©   (03.01.06 1:12) [5]
плагин может быть написан и на Delphi, и на C++, на чем угодно, что может вызывать WinApi функции и компилировать библиотеки DLL.


то есть, фактически НИКАКИХ объектов, так как .NET не планируется.

Desdechado ©   (03.01.06 11:30) [11]
Обязательно при передаче хэндлов (если ты хочешь именно по-своему сделать) помни, что компилироваться твоя прога и плагины должны на ИДЕНТИЧНЫХ версиях


да НЕ БУДЕТ плагин знать о том, что Handle - это ссылка на TQuery. Для плагина это как объект ядра программы. Handle можно и не ссылкой на TQuery делать, а рандомно генерить, просто так удобно и обеспечивается уникальность Handle...


 
Sergey Masloff   (2006-01-03 13:00) [13]

Piter ©   (03.01.06 12:51) [12]
>плагин может быть написан и на Delphi, и на C++,
Да я это просмотрел. Тогда какие к фигам Query? Их просто не существует в це бейсики и вообще нигде кроме борланда.
Тогда можно использовать или рекордсеты ADO (но соответственно ADO нужно) или все данные отдавать в raw виде - ну там массив OLE Variants или самому конструировать строку вида

<rowset name = "custom name">
 <row>
   <col kind="myint" name = "field1">field1value</col>
   <col kind="mystr" name = "field2">field2value</col>
   ....
 </row>
 ....
</rowset>

выделять под нее память и отдавать указатель на нее и размер плагину. А там пусть разбирает как хочет


 
Piter ©   (2006-01-03 13:32) [14]

Sergey Masloff   (03.01.06 13:00) [13]
Тогда какие к фигам Query?


Эх... Сергей!!! Перечитай плиз первые мои два поста!!!

О TQuery я говорил в том смысле - КАК сама работа с базой будет в ядре осуществляться. А плагин то понятное дело ни о каких TQuery и не знает.

Твою идею понял - возвращать весь набор данных в виде аля XML... Но а вдруг запрос вернет тысячи записей??? А если вдруг миллион? На формирование такого списка уйдет безумная куча времени и ресурсов... Мне пока мой способ нравится больще.

Итак, еще раз мой способ.

Это как бы перенос идеи объекта ядра из Windows. То есть, плагин создает объект ядра:

CreateRequest("SQL запрос");

Ему возвращается Handle. Далее используя этот Handle он может оперировать с открытым набором данных, как то:

GetIntegerParam(Handle, "ParamName"): integer

SetPosition(Handle, spNext): boolean

вместо spNext там: spBack, spFirst, spLast.

В САМОМ же движке это может быть наглядно реализовано, например:

function CreateRequest(SQLRequest: PChar): THandle; stdcall;
var
 query: TQuery
 s: string;
begin
 s := SQLRequest;
 query := SQLManager.CreateQuery;
 if query = nil then
   Result := 0
 else
 begin
   query.SQL.add(s);
   query.Open;
   Result := THandle(Pointer(Query));
 end;

Или типа подобного, я сейчас от руки набросал - но думаю понятно.


 
Piter ©   (2006-01-03 13:38) [15]

Возникает пока 1 вопрос по МОЕМУ способу:

хотелось бы универсальной функции: CreateRequest, то есть, которая принимала бы и SELECT запросы, и INSERT, UPDATE и так далее, преобразовывая в вызовы нужных методов TQuery: Open или ExecSQL.


 
Piter ©   (2006-01-03 13:41) [16]

В общем, я так понял мое направление правильное :)
Сергей мыслит бизнес-процессами, поэтому предполагает использование серъезных технологий, а у меня тут не так :)

Думаю, это самое оптимальное - использование TQuery и предоставление доступа к нему как к объекту ядра, то есть плагин просто каждый раз будет передавать Handle и вызывать нужные ему функции по работе с данными.

А в конце вызывается: CloseRequest(Handle) и тогда в ядре программы соответствующий объект TQuery уничатожается...

Если кто что понял - покритикуйте :)


 
Sergey Masloff   (2006-01-03 13:46) [17]

Нет непонятно.
1) при чем тут вообще THandle - дельфийский псевдоним для Integer
2) если запрос вернет несколько тысяч записей ресурсов при использовании T(IB)Query уйдет не меньше а как бы и не больше чем в моем варианте
3) Ты собираешься держать тучу открытых запросов еще и с навигацией по ним. Причем если у тебя плагин отвалится то ты об этом никогда не узнаешь и открытый запрос останется навеки

Вобщем, идея мертвая. ИМХО. Дерзай может что и получится


 
Desdechado ©   (2006-01-03 13:50) [18]

ты для каждого плага собираешься свое множество квериков хранить (т.е. разделять будешь) или общий пул на всех (а как тогда с "чужими" некорректные операции)?


 
Sergey Masloff   (2006-01-03 13:57) [19]

Piter ©   (03.01.06 13:38) [15]
>хотелось бы универсальной функции: CreateRequest, то есть, которая >принимала бы и SELECT запросы, и INSERT, UPDATE и так далее, >преобразовывая в вызовы нужных методов TQuery: Open или ExecSQL
Тут проблем нет есть свойство StatementType или что-то в этом роде возвращает перечислимое значение с типом выражения нк там INSERT или скажем DDL или DELETE


 
Piter ©   (2006-01-03 13:58) [20]

Sergey Masloff   (03.01.06 13:46) [17]
1) при чем тут вообще THandle - дельфийский псевдоним для Integer


ну просто ссылки на объекты ядра обычно имеют в Delphi возвращаемый тип YHandle, вот и все. Например: CreateMutex, CreateSemaphore :)

Можно с таким же успехом просто LongWord использовать

Sergey Masloff   (03.01.06 13:46) [17]
2) если запрос вернет несколько тысяч записей ресурсов при использовании T(IB)Query уйдет не меньше а как бы и не больше чем в моем варианте


хм... почему?

В твоем варианте я считаю кучу времени уйдет на формирование ИЗ набора даных текстовых XML строк. А у меня?

Sergey Masloff   (03.01.06 13:46) [17]
Ты собираешься держать тучу открытых запросов еще и с навигацией по ним


а какие еще варианты? Ведь может быть несколько плагинов, каждый вправе использовать базу данных...

Sergey Masloff   (03.01.06 13:46) [17]
Причем если у тебя плагин отвалится то ты об этом никогда не узнаешь и открытый запрос останется навеки


а что значит плагин отвалится? Выгрузится DLL-библиотека из адресного пространства? Сам себя что ли плагин выгрузит?


 
Piter ©   (2006-01-03 14:04) [21]

Desdechado ©   (03.01.06 13:50) [18]
ты для каждого плага собираешься свое множество квериков хранить


собственно, как видно выше, поводом к созданию TQuery является подача команды из плагина. Handle создаваемого TQuery передается в конкретный плагин, по завершению работы с базой плагин может "закрыть" объект ядра, что приведет к уничатожению этого TQuery. Поэтому сколько плагин захочет таких объектов создать, столько и будет.

Собственно, с другой стороны - один плагин может вполне обойтись одним своим TQuery.

Sergey Masloff   (03.01.06 13:57) [19]
Тут проблем нет есть свойство StatementType или что-то в этом роде возвращает перечислимое значение


это свойство есть у TQuery?

Тогда не в тему, но странно - а зачем в самом TQuery разделили процедуры Open и ExecSQL?


 
Sergey Masloff   (2006-01-03 14:11) [22]

2) Потому что (IB)Query расходует кучу ресурсов на поддержку двунаправленых курсоров. Так что прочитать все через компоненты без этого оверхеда и завернуть все в строковый буфер врядли сильно медленннее. Кроме того тот же IBQuery упадет с EOutOfMemory гораздо раньше чем пойдет речь о десятках тысяч записей.

>Ведь может быть несколько плагинов, каждый вправе использовать базу >данных...
Как обычно спросил->данные получил->отвалился. И так все хоть 100 штук одновременно

>а что значит плагин отвалится?
Да что угодно. Потеряет плагин твой хендл и все. Вариантов масса - от простых ошибок до умелого применения try except<пусто><end>


 
Piter ©   (2006-01-03 14:27) [23]

Sergey Masloff   (03.01.06 14:11) [22]
Да что угодно. Потеряет плагин твой хендл и все


не, ну знаешь, уверен, что в твоем способе тоже плагин может намудрить - насоздавать там кучу провайдеров или еще чего-нибудь (я просто не разбираюсь) - это и так понятно.

Тоже самое, что процесс в Windows может наоткрывать кучу файлов, насоздовать кучу окон - все будет тормозить, но система ничего с этим поделать не в состоянии - а может прада процессу столько нужно?

Так что тут вопрос такой... В конце концов плагин работает в ВАП моего процесса, поэтому при "умелом" программировании он полюбому сможет убить ядро программы, тут как ни крутись...

Sergey Masloff   (03.01.06 14:11) [22]
Как обычно спросил->данные получил->отвалился


Да, тут согласен, в моем варианте ПЛАГИН должен закрывать TQuery, это как недостаток при неумелом программировании, так и достоинство при умелом.

Sergey Masloff   (03.01.06 14:11) [22]
Кроме того тот же IBQuery упадет с EOutOfMemory гораздо раньше чем пойдет речь о десятках тысяч записей


хм... сча потестю :)


 
Piter ©   (2006-01-03 17:22) [24]

Sergey Masloff   (03.01.06 14:11) [22]
Кроме того тот же IBQuery упадет с EOutOfMemory гораздо раньше чем пойдет речь о десятках тысяч записей


сейчас руки дошли.

Итак, в таблице post всего записей: 17610

При этом запрос:

IBQuery1.SQL.Add("Select * from post");

Выполняется быстро и никаких нехваток памяти.


 
Sergey Masloff   (2006-01-03 18:06) [25]

Piter ©   (03.01.06 17:22) [24]
Last() сделал? ;-)
Если нет то и говорить не о чем. По моим (давним) наблюдениям предел размера буфера порядка 5 Мб.


 
Piter ©   (2006-01-03 18:11) [26]

Sergey Masloff   (03.01.06 18:06) [25]

сделал


 
Piter ©   (2006-01-03 18:17) [27]

Sergey Masloff   (03.01.06 18:06) [25]

Last сделал, тестировал на стандартном D7.
Записей в таблице: 17610

Вроде никаких таких тормозов и ошибок памяти.

Единственное что - использовал для тестов Embedded версиб FB, локальную. Но это должно быть пофигу я думаю для TQuery - ему то откуда знать.


 
Piter ©   (2006-01-03 18:19) [28]

Sergey Masloff   (03.01.06 18:06) [25]
По моим (давним) наблюдениям предел размера буфера порядка 5 Мб.


в этом наверное дело, вся база занимает: 11,2 Mb

Там 2 больших таблицы и несколько мелких (очень мелких). Тестируемая таблица самая большая, но видимо не дотягивает...

Тогда надо таблицу на сотню тысяч записей взять... У меня такой под рукой нету :(


 
Piter ©   (2006-01-03 18:20) [29]

генерировать влом, но потом может потестю :)


 
Sergey Masloff   (2006-01-03 18:25) [30]

Ты сделай select * from big_table, small_table
получишь m*n записей ;-)))))
только 2 раза большую не множь а то устанешь ждать
Кстати может в новых IBX подняли размеры? Надо будет посмотреть. Я в 2003 году явление наблюдал - у меня начали клиенты стали сообщать об ошибке при одной из операций, в результате очень долгих тестовых мук было установлено что дело в IBQuery (или IBDataSet) и ограничении его внутр. буфера.



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2006.02.26;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.042 c
15-1139380388
race1
2006-02-08 09:33
2006.02.26
Бесплатная программа


3-1136373203
кот
2006-01-04 14:13
2006.02.26
Выбор оптимальной базы данных


15-1138667087
Petr V. Abramov
2006-01-31 03:24
2006.02.26
Россияне не должны стать ИТ-батраками


8-1127071368
Sysanin
2005-09-18 23:22
2006.02.26
...быстро перемещать картинку...


2-1139215867
G@rik
2006-02-06 11:51
2006.02.26
Что нужно, чтобы работал exe-шник?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский