Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.10.30;
Скачать: CL | DM;

Вниз

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

 
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;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.057 c
2-1128534097
The Sound
2005-10-05 21:41
2005.10.30
Ошибка, при использовании ShellApi.


3-1126973127
Tonich
2005-09-17 20:05
2005.10.30
Числа в базе данных


14-1129110358
-=S..S=-
2005-10-12 13:45
2005.10.30
А чё ветку орешник не обновляют ? :(


14-1129016372
KilkennyCat
2005-10-11 11:39
2005.10.30
У кого-нибудь квартира в Петербурге в аренду есть?


2-1128433327
Fidel
2005-10-04 17:42
2005.10.30
Проблема с генератором