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

Вниз

Коннект к базе в дополнительном потоке   Найти похожие ветки 

 
Piter ©   (2005-08-29 23:50) [0]

Вот думаю - как правильно реализовать соединение с базой в отдельном потоке.

Допустим, есть класс от TThread... Но как им управлять?
Хочется реализовать так, чтобы ему можно было дать любое SQL выражение, он его выполнит. Ну если с INSERT, UPDATE понятно... То что делать с SELECT? Как поток вернет набор данных?


 
Reindeer Moss Eater ©   (2005-08-30 00:18) [1]

Вернет.
А куда он денется с подводной-то лодки?


 
Alexander Panov ©   (2005-08-30 00:30) [2]

Piter ©   (29.08.05 23:50)

Схематично:

TQueryComplete=procedure(Query: TQuery) of object;

TQueryThread=class(Tthread)
private
  FDB: TDatabase;
  FQuery: TQuery;
  FStr: String;
  FOnComplete: TQueryComplete;
protected
  procedure Execute; override;
public
  procedure ExecQuery(const Query: String);
  property OnComplete: TQueryComplete read FOnComplete write FOnComplete;
end;

procedure TQueryThread.Execute;
begin
  FDB := TDatabase.CReate(nil);
  ...
  FQuery := TQuery.CReate;
  ...
  Suspend;
  while not Terminated do
  begin
    try
       FQuery.Close;
       FQUery.Sql.Text := FStr;
       if UpperCase(Copy(FStr,1,6))="SELECT"
         then FQuery.Open
         else FQuery.ExecSql;
    except
    end;
    if Assigned(FOnComplete) then FOnComplete(FQuery);
    Suspend;
  end;
end;

procedure TQueryThread.ExecQuery(const Query: String);
begin
  FStr := Query;
  Resume;
end;


Примерно так можно.


 
Reindeer Moss Eater ©   (2005-08-30 00:35) [3]

Вообще TDataSet является threadsafe классом.
Надо лишь визуальные контролы подключать к нему после открытия.


 
Piter ©   (2005-08-30 01:42) [4]

Ну вот допустим такой вопрос...

Связь с базой данных медленная - плохой канал связи там или например операция с базой выполняется длительное время.

Соответственно какой-нибудь оператор Query.ExecSQL может повесить приложение на несколько минут, интерфейс недоступен - нехорошо.

Выход - работать с базой в потоке, ок.
Но возникает вопрос - а как "нормально" прервать данный процесс? Например, если приложение надо срочно закрыть?

Если сделали Query.ExeSQL и идет работа - думаю, некорректно будет из другого потока делать Query.Free? А что же тогда делать? Какая-то безвыходная ситуация...

Или вот способо прервать - это сделать TDatabase.Connect := false... но опять же - когда идет работа - разве корректно будет из другого потока делать Database.Connect := false?


 
Карелин Артем ©   (2005-08-30 06:03) [5]

Если очень надо - уничтожай поток. Некоторые товарищи писали что это неправильно, однако аргументов по этому поводу не предоставляли. :)


 
Alexander Panov ©   (2005-08-30 08:52) [6]

Piter ©   (30.08.05 1:42) [4]
Free для доп. потока теюе не поможет, как и Database.Close.
Только TerminateThread.


 
Piter ©   (2005-08-30 13:22) [7]

То есть, нормального способа прервать длительную операцию нет?

Блин... неправильно это как-то... нелогично. Неужели не предусмотрели...


 
Val ©   (2005-08-30 13:30) [8]

...однако аргументов по этому поводу не предоставляли...
Аргумент стандартен: Что SQL сервер знает о клиентских потоках?


 
Alexander Panov ©   (2005-08-30 13:38) [9]

Val ©   (30.08.05 13:30) [8]
Что SQL сервер знает о клиентских потоках?


А ему оно надо?


 
Val ©   (2005-08-30 13:42) [10]

не думаю. поэтому он спокойно колбасит себе свои запросы и далее.


 
ANB ©   (2005-08-30 14:04) [11]

Для асинхронки выход один (имхо) - уходить на специфичные для нужного сервера методы доступа. Для Oracle и MS SQL поддерживается асинхронка. Вывод длительных запросов в отдельный поток решает только проблему неподвисания интерфейса, но снять такой запрос будет проблематично. В ADO есть возможность организовать асинхронное выполнение без отдельных потоков, но, во первых, работает не всегда, во вторых - я все равно не нашел, как прервать такую операцию.


 
Anatoly Podgoretsky ©   (2005-08-30 14:17) [12]

Alexander Panov ©   (30.08.05 13:38) [9]
Хотелось бы, что бы от этого сервер не вставал колом, когда пьяный программист вдруг возьмем и грохнет все. Случаи известны.


 
ANB ©   (2005-08-30 14:21) [13]


> Anatoly Podgoretsky ©   (30.08.05 14:17) [12]
- ну, оракла может стать колом даже при снятии сессии, смотря что в ней гоняли, гы. Тут уже никакая асинхронка не поможет.


 
isasa ©   (2005-08-30 15:55) [14]

Никто не вспомнил?

{ CoInitFlags determines the COM threading model of the application or current
 thread. This bitflag value is passed to CoInitializeEx in ComServ initialization.
 Assign COINIT_APARTMENTTHREADED or COINIT_MULTITHREADED to this variable before
 Application.Initialize is called by the project source file to select a
 threading model.  Other CoInitializeEx flags (such as COINIT_SPEED_OVER_MEMORY)
 can be OR"d in also.  }
var
 CoInitFlags: Integer = -1;  // defaults to no threading model, call CoInitialize()


 
Piter ©   (2005-08-30 16:34) [15]

теперь осталось разъяснить, причем здесь COM


 
isasa ©   (2005-08-30 16:41) [16]

А ComObj используем.
Имеем(по умолчанию) - CoInitialize(),
надо - CoInitializeEx( COINIT_MULTITHREADED ), или хотя бы CoInitializeEx( COINIT_APARTMENTTHREADED )


 
Piter ©   (2005-08-30 17:46) [17]

isasa ©   (30.08.05 16:41) [16]
А ComObj используем


не понял. Кто ComObj использует?

Народ!

Вот что придумал. Итак, задаем запрос потоку, он соединяется с базой, выполняет запрос. А потом в Synchronize процедуре возвращает ссылку на Query.Fields - так подойдет?

Если Query создан в доп. потоке, то можно к Query.Fields обращаться в основном потоке для извлечения значения полей?


 
Карелин Артем ©   (2005-08-30 19:29) [18]


> Val ©   (30.08.05 13:42) [10]

Вообще-то он прекращает выполнение запросов в этом случае. По крайней мере в моем софте.


 
Piter ©   (2005-08-30 20:12) [19]

Piter ©   (30.08.05 17:46) [17]
Народ!

Вот что придумал. Итак, задаем запрос потоку, он соединяется с базой, выполняет запрос. А потом в Synchronize процедуре возвращает ссылку на Query.Fields - так подойдет?


Отвечаю сам себе - да, подойдет! Видимо, единственный грамотный способ вернуть полученные данные в другой поток


 
Карелин Артем ©   (2005-08-30 20:33) [20]


> Piter ©   (30.08.05 20:12) [19]

А поток как долго будет после этого жить? Может в какой-нибудь набор данных в памяти скапировать данные?


 
Piter ©   (2005-08-30 21:02) [21]

Карелин Артем ©   (30.08.05 20:33) [20]
А поток как долго будет после этого жить?


дык потос Syncronize вызывает - соответственно, замрет на это время

Карелин Артем ©   (30.08.05 20:33) [20]
Может в какой-нибудь набор данных в памяти скапировать данные?


а вот это интересно. Если перекопировать переданный Query.Fields в другой TFields - нормально будет?


 
Alexander Panov ©   (2005-08-30 23:45) [22]

Piter ©   (30.08.05 20:12) [19]
Видимо, единственный грамотный способ вернуть полученные данные в другой поток


Хм. видимо мой пример неправильный и TQuery в нем ни в какую нельзя использовать.


 
Piter ©   (2005-08-31 00:42) [23]

Alexander Panov ©   (30.08.05 23:45) [22]

твой пример неправильный тем, что вызываешь обработчик событие в доп. потоке, что чревато. Стараются делать VCL совместимое все.

А вот насчет передачи Query через Synchronize тоже чревато - ибо юзер может и Open сделать, и ExecSQL и т.д.
А с TFields особо ничего не сотворишь... пока мне так кажется...


 
Fay ©   (2005-08-31 03:43) [24]

2 Piter ©   (29.08.05 23:50)
При фетче легко можно получить что-нибудь типа "Connection is busy"
З.Ы.
Я не дружу с американским 8(


 
Fay ©   (2005-08-31 03:44) [25]

К Fay ©   (31.08.05 3:43) [24]

... в случае одного Connection-образного экземпляра для неск. потоков


 
Карелин Артем ©   (2005-08-31 05:36) [26]

ClientDataSet1.FieldDefs.Assign(IBQuery1.FieldDefs);
ClientDataSet1.CreateDataSet;
ClientDataSet1.Open;
IBQuery1.First;
while not(IBQuery1.Eof) do
 begin
  ClientDataSet1.Append;
   for i:=0 to IBQuery1.FieldCount-1 do
   begin
    ClientDataSet1.Fields[i].Value:=IBQuery1.Fields[i].Value;
   end;
  ClientDataSet1.Post;
  IBQuery1.Next;
 end;//while


 
Alexander Panov ©   (2005-08-31 09:03) [27]

Piter ©   (31.08.05 0:42) [23]
твой пример неправильный тем, что вызываешь обработчик событие в доп. потоке, что чревато. Стараются делать VCL совместимое все.


Пример был не для того, чтобы его использовать напрямую.

Piter ©   (31.08.05 0:42) [23]
А вот насчет передачи Query через Synchronize тоже чревато - ибо юзер может и Open сделать, и ExecSQL и т.д.


Ты о чем? Какой юзер? Программу пишешь ты а не юзер.
Просмотрел всю ветку сначала, не нашел слова "юзер" ни в одном посте.


 
Alexander Panov ©   (2005-08-31 09:04) [28]

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


 
Piter ©   (2005-09-18 00:05) [29]

А теперь такой вопрос - а если нужно передавать данные SELECT"а в стороннюю DLL (плагин) - то как поступать? То есть, движок базы реализован в самой программн, плагин в виде DLL делает запрос - ок... а как ему вернуть данные?
Надо учесть, что плагин и на C++ может быть написал, и на D, и на чем угодно...



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

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

Наверх




Память: 0.52 MB
Время: 0.036 c
2-1128164730
Yura32
2005-10-01 15:05
2005.10.30
Memo


5-1106759236
Митяй2
2005-01-26 20:07
2005.10.30
Как знать, что мышь покинула кнопку?


14-1129061365
saNat
2005-10-12 00:09
2005.10.30
Куда все катится...


1-1128359842
DimaT
2005-10-03 21:17
2005.10.30
ReadComponent / WriteComponent


2-1128674268
Денис
2005-10-07 12:37
2005.10.30
Обратный результат.





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский