Текущий архив: 2002.12.26;
Скачать: CL | DM;
ВнизВынесение запроса к базе в поток Найти похожие ветки
← →
BorisUK (2002-12-06 07:55) [0]У меня трехзвенка, хочу вынести запрос с клиента к базе в поток...
Что делаю не так?
Почитал архив - там на все вопросы такого типа "Что сделать чтоб запрос можно было прервать?", "Чтоб прога не подвисала на время выполнения запроса?"
Все советовали поток... ОК
Создал.
В общем поток запускается (о чем сигнализирует метод монитор, показывая какой запрос пошел исполнятся),
какоето время обрабатывыет, а потом выдается ошибка
"Error reading from Socket" такая же ошибка сразу при попытке прервать поток...
При запуске из делфи дебагер перед этой ошибкой успевает еще сказать:
raised exception class EVariantError with message "Variant is not an array"
Еще можно сказать что эта ошибка происходит гдето окромя
запуска потока и непосредственно выполнения запроса, так как там траями отлавливаю, но та ошибка не оттуда выскакивает...
Помогите кто был успешнее в этом деле...
За рабочий пример буду блаодарен больше жизни :)
unit SQLExecThread;
interface
uses
Classes, dm_u, sysutils, wait_u;
type
TSQLExecThread = class(TThread)
private
StrMes : String;
{ Private declarations }
protected
procedure Execute; override;
procedure Monitor;
public
procedure SetSQL(s : String);
end;
implementation
var
SQLText : String;
procedure TSQLExecThread.SetSQL(s : String);
begin
SQLText:= s;
end;
procedure TSQLExecThread.Monitor;
begin
Wait_f.Label1.Caption:= StrMes;
end;
procedure TSQLExecThread.Execute;
var
i : integer;
begin
try
StrMes:=SQLText;
Synchronize(Monitor);
dm.ClientDataSet1.Active:=false;
dm.ClientDataSet1.CommandText:=SQLText;
dm.ClientDataSet1.Active:=true;
except
on E: Exception do
begin
StrMes:="шибка из потока "+e.Message;
Synchronize(Monitor);
end;
end;
if Terminated then
begin
exit;
end
end;
end.
Из главного окна проги делаю обработчик на кнопку
procedure TMain_f.bb_FindPPClick(Sender: TObject);
var
s : String;
begin
s:="Select * from Table1";
try
SQLExecThrd:=TSQLExecThread.Create(true);
SQLExecThrd.SetSQL(s);
SQLExecThrd.Resume;
SQLExecThrd.Priority:=tpLowest;
except
on E:Exception do
Showmessage("Ошибка в главном модуле "+e.message);
end;
//Вначале сделал вот так, но так виснет сразу
{ finally
SQLExecThrd.Terminate;
SQLExecThrd.Free;
end;}
end;
// Прерывание потока
procedure TMain_f.bb_BreakClick(Sender: TObject);
begin
if SQLExecThrd.Suspended then
SQLExecThrd.Resume;
SQLExecThrd.Terminate;
end;
← →
ЮЮ (2002-12-06 08:16) [1]а dm.ClientDataSet1 синхронизировать не надо?
И это называется трехзвенка, когда клиент изменяет текст запроса?
Суть ClientDataSet-а, по-моему, в том, чтобы брать данные у Провайдера, а тот в свою очередь работал с сервером БД
← →
BorisUK (2002-12-06 08:19) [2]Я примерно так и понял, что ктото чтото теперь не успевает передать,
но как синхронизировать... подскажите плз а то у меня затмение :(
← →
sniknik (2002-12-06 08:25) [3]ну есть пару вещей которые я бы изменил (применительно к потоку), по базе думаю это только наметки (проба), а так вроде все нормально.
try
try
SQLExecThrd:=TSQLExecThread.Create(true);
SQLExecThrd.SetSQL(s);
SQLExecThrd.Priority:=tpNormal; //а то тормозить будет
SQLExecThrd.FreeOnTerminate:= false; //чтобы работало завершение как у тебя
SQLExecThrd.Resume;
except
on E:Exception do
Showmessage("Ошибка в главном модуле "+e.message);
end;
// вот это теперь должно работать от FreeOnTerminate
finally
SQLExecThrd.Terminate;
SQLExecThrd.WaitFor; //ждать окончания запроса пока не отработал убивать нельзя
SQLExecThrd.Free;
end;
ну и бработчик в "скобочки" хотя и без этого работает проверял но в хелпе пишут так надо
procedure TSQLExecThread.Execute;
var
i : integer;
begin
CoInitialize(nil);
... код //но его бы посложней просто один запрос можно и асинхронно выполнить чтобы не тормозило
CoUnInitialize();
end;
← →
BorisUK (2002-12-06 09:12) [4]CoInitialize(nil);
CoUnInitialize();
На них матерится.. говорит
-- Undeclared identifier: "CoInitialize"
А так в общем заработало, но как попало :(
Помогли оба совета...
<<ЮЮ ©
Синхронизировал вроде - хотя может не то сделал...
Вынес получение данных в процедуру потока
procedure TSQLExecThread.ResiveData;
begin
dm.CDS_V_DocTree.Active:=true;
wait_f.close;
end;
В execute вызываю её
procedure TSQLExecThread.Execute;
var
i : integer;
begin
try
// CoInitialize(nil);
dm.CDS_V_DocTree.Active:=false;
dm.CDS_V_DocTree.CommandText:=SQLText;
Synchronize(ResiveData);
except
on E: Exception do
begin
StrMes:=e.Message;
Synchronize(Monitor);
end;
end;
if Terminated then
begin
wait_f.close;
exit;
end;
// CoUnInitialize();
end;
Но теперь все работает как до потока было...
Пока данные не получатся вся прога подвисает...
У меня перед запуском потока вызывается формочка с програссбаром, на ней таймер который задает движение на прогрессбаре (чтоб юзеру не скучно было) Так вот он теперь тоже не идет ... Тоесть пока
dm.CDS_V_DocTree.Active:=true не выполнится
зависает все :(
В общем для чего старался - чтоб запрос прерывать можно было и визуализировать процесс ожидания - Того и не вышло пока...
Может что ещё подскажете?
← →
sniknik (2002-12-06 11:18) [5]логику поменяй. не жди завершения, к примеру можно открывать поток в начале проги и закрывать в конце управляя им по "ходу пьесы", при открытии пускать процесс, а при завершении запроса генерить событие.
посмотри еще хелп по ADODataSet.ExecuteOptions может это тебе больше подойдет.
Страницы: 1 вся ветка
Текущий архив: 2002.12.26;
Скачать: CL | DM;
Память: 0.47 MB
Время: 0.006 c