![]() |
Re: Datenbankabfragen mit Threads?
Sybase kann definitiv mit mehreren Connections umgehen.
BTW hat den gleichen Ursprung wie der MSSQL-Server |
Re: Datenbankabfragen mit Threads?
Damit sich irgendetwas während der Abfragen auf dem Formularfeld "bewegt". In dem Fall eine Uhr in der Statusleiste.
Es ist eine Embedded Variante die zusammen mit einer Software geliefert wird. |
Re: Datenbankabfragen mit Threads?
Solange obiger Quellcode keine Fehlermeldung verursacht vewendest du keine Threads, da:
1, Kein passendes Threading-Appartment für das COM-Subsystem angemeldet wird 2, Du keinerlei vorkehrungen hast die Connection (hier vor allem das COM-Interface) entsprechend für den Thread zu marshallen. |
Re: Datenbankabfragen mit Threads?
Zitat:
Delphi-Quellcode:
Das soll mal ein Gerüst darstellen. Kommuniziert wird hier über Messages, was aber innerhalb der Klasse bleibt. Ich habe Messages gewählt, weil ich mir nicht sicher bin, ob das die ADO-Komponenten benötigen.
interface
uses Classes, AdoDB, Windows, Messages, ActiveX; const DM_Base=WM_User; DM_Ask=DM_Base+1; DM_Next=DM_Base+2; DM_Last=DM_Next; type TSqlEvent=procedure(answer:integer) of object; type TOpenQuery = Class(TThread) Public constructor Create(AConnectString:WideString; //as is AonTerminate:TNotifyEvent; //wird ausgelöst, wenn Thread beendet oder abbricht AOnSqlEvent:TSqlEvent); //wird ausgelöst, wenn neues Datenbankergebnis procedure Terminate; override; //Thread beenden function AskSQL(aSqlText:string):boolean; //neues SQL_Statement function NextSQL:boolean; //=SQLQuery.Next protected FQry: TADOQuery; FCon: TADOConnection; FSql: String; FConnectString: WideString; FOnSQLEvent:TSQLEvent; FAnswer:Integer; procedure Execute; override; procedure DoSQLCommand(var msg:TMessage); message DM_Ask; procedure DoSQLNext(var msg:TMessage); message DM_Next; procedure DoSQLEvent; end; implementation constructor TOpenQuery.Create(); begin inherited Create(False); FreeOnTerminate:=True; FConnectString:=aConnectString; onTerminate:=AonTerminate; FOnSQLEvent:=AOnSQLEvent; end; procedure TOpenQuery.Execute; var msg:TMSG; begin coinitialize(nil); FCon:=TAdoConnection.Create(nil); Fqry:=TAdoQuery.Create(nil); try FCon.ConnectionString:=FconnectString; Fqry.Connection:=FCon; FCon.Open; while not terminated and getmessage(msg,0,0,0) do begin if (msg.message>=DM_Base)and (msg.message<=DM_Last) then dispatch(msg) //Als message an die Klasse verteilen else dispatchmessage(msg); //Windows verteilen lassen end; finally Fqry.Free; FCon.Free; CoUninitialize; end; end; procedure TOpenQuery.Terminate; begin inherited; PostThreadMessage(self.ThreadID,WM_quit,0,0); //getmessage abbrechen end; procedure TOpenQuery.DoSQLCommand(var msg:TMessage); var sqltext:PString; begin sqlText:=PString(msg.LParam); Fqry.active:=false; Fqry.SQL.Text:=sqlText^; dispose(sqlText); Fqry.Open; if not Fqry.eof then begin FAnswer:=Fqry.FieldByName('zahl').AsInteger; synchronize(DoSQLEvent); end; //else Maintthread informieren end; procedure TOpenQuery.DoSQLNext(var msg:TMessage); begin if (Fqry.Active)and (not Fqry.Eof) then begin Fqry.Next; FAnswer:=Fqry.FieldByName('zahl').AsInteger; synchronize(DoSQLEvent); end;// else an MainThread melden end; procedure TOpenQuery.DoSQLEvent; begin if assigned(FonSQLEvent) then FOnSQLevent(FAnswer); end; function TOpenquery.AskSQL(ASqlText:string):boolean; var SQLText:PString; begin new(SQLText); SQLTExt^:=ASqlText; result:=PostThreadMessage(self.ThreadID,DM_Ask,0,integer(SQLText)); if not result then dispose(SQLTExt); end; function TOpenQuery.NextSQL; begin result:=PostThreadMessage(self.ThreadID,DM_Next,0,0); end; Auf jeden Fall muss man hier noch einige Sicherheiten einbauen. Insbesondere, da bei Auftreten eines Fehlers, der Thread einfach beendet wird und dein Mainthread das maximal über die onTerminate-Routine mitbekommt. |
Re: Datenbankabfragen mit Threads?
Zitat:
Delphi-Quellcode:
Das soll mal ein Gerüst darstellen. Kommuniziert wird hier über Messages, was aber innerhalb der Klasse bleibt. Ich habe Messages gewählt, weil ich mir nicht sicher bin, ob das die ADO-Komponenten benötigen.
uses Classes, AdoDB, Windows, Messages, ActiveX;
const DM_Base=WM_User; DM_Ask=DM_Base+1; DM_Next=DM_Base+2; DM_Last=DM_Next; type TSqlEvent=procedure(answer:integer) of object; type TOpenQuery = Class(TThread) Public constructor Create(AConnectString:WideString; //as is AonTerminate:TNotifyEvent; //wird ausgelöst, wenn Thread beendet oder abbricht AOnSqlEvent:TSqlEvent); //wird ausgelöst, wenn neues Datenbankergebnis procedure Terminate; reintroduce; //Thread beenden function AskSQL(aSqlText:string):boolean; //neues SQL_Statement function NextSQL:boolean; //=SQLQuery.Next protected FQry: TADOQuery; FCon: TADOConnection; FSql: String; FConnectString: WideString; FOnSQLEvent:TSQLEvent; FAnswer:Integer; procedure Execute; override; procedure DoSQLCommand(var msg:TMessage); message DM_Ask; procedure DoSQLNext(var msg:TMessage); message DM_Next; procedure DoSQLEvent; end; implementation constructor TOpenQuery.Create; begin inherited Create(False); FreeOnTerminate:=True; FConnectString:=aConnectString; onTerminate:=AonTerminate; FOnSQLEvent:=AOnSQLEvent; end; procedure TOpenQuery.Execute; var msg:TMSG; VCLmsg:TMessage; begin coinitialize(nil); FCon:=TAdoConnection.Create(nil); Fqry:=TAdoQuery.Create(nil); try FCon.ConnectionString:=FconnectString; Fqry.Connection:=FCon; FCon.Open; while not terminated and getmessage(msg,0,0,0) do begin if (msg.message>=DM_Base)and (msg.message<=DM_Last) then begin VCLmsg.Msg:=msg.message; VCLmsg.LParam:=msg.lParam; VCLmsg.WParam:=msg.wParam; VCLmsg.Result:=0; dispatch(VCLmsg) //Als message an die Klasse verteilen end else dispatchmessage(msg); //Windows verteilen lassen end; finally Fqry.Free; FCon.Free; CoUninitialize; end; end; procedure TOpenQuery.Terminate; begin inherited; PostThreadMessage(self.ThreadID,WM_quit,0,0); //getmessage abbrechen end; procedure TOpenQuery.DoSQLCommand(var msg:TMessage); var sqltext:PString; begin sqlText:=PString(msg.LParam); Fqry.active:=false; Fqry.SQL.Text:=sqlText^; dispose(sqlText); Fqry.Open; if not Fqry.eof then begin FAnswer:=Fqry.FieldByName('zahl').AsInteger; synchronize(DoSQLEvent); end; //else Maintthread informieren end; procedure TOpenQuery.DoSQLNext(var msg:TMessage); begin if (Fqry.Active)and (not Fqry.Eof) then begin Fqry.Next; FAnswer:=Fqry.FieldByName('zahl').AsInteger; synchronize(DoSQLEvent); end;// else an MainThread melden end; procedure TOpenQuery.DoSQLEvent; begin if assigned(FonSQLEvent) then FOnSQLevent(FAnswer); end; function TOpenquery.AskSQL(ASqlText:string):boolean; var SQLText:PString; begin new(SQLText); SQLTExt^:=ASqlText; result:=PostThreadMessage(self.ThreadID,DM_Ask,0,integer(SQLText)); if not result then dispose(SQLTExt); end; function TOpenQuery.NextSQL; begin result:=PostThreadMessage(self.ThreadID,DM_Next,0,0); end; Auf jeden Fall muss man hier noch einige Sicherheiten einbauen. Insbesondere, da bei Auftreten eines Fehlers, der Thread einfach beendet wird und dein Mainthread das maximal über die onTerminate-Routine mitbekommt. |
Re: Datenbankabfragen mit Threads?
Danke erstmal für die aufwändige Antwort. Es erscheint mir sehr kompliziert, das muss ich in Ruhe durchprobieren. Dachte echt das geht einfacher. Ich brauch keine Multiabfragen, sondern einfach nur eine Datenbankabfrage nach der nächsten. Solange wie eine Abfrage läuft, soll sich in meinem Hauptformular irgendetwas bewegen (in dem Fall soll die Uhr weiter laufen). Nach der Abfrage möchte ich von meinem Hauptformular die Daten weiterverarbeiten. Vielleicht bekomme ich es mit dem oben genannten Ansatz hin, wobei ich in Threads noch absoluter Greenhorn bin.
|
Re: Datenbankabfragen mit Threads?
ADO (oder wars nur der MS SQL Server über ADO) kann die Ergebnisdatenmenge (wenn sie z.B. in einem Grid benötigt wird) asynchron zurückliefern. Ob das auch der Provider von Sybase kann weis ich nicht.
|
Re: Datenbankabfragen mit Threads?
Also wenn ich eine Abfrage hätte, die 15 Sekunden dauert, dann würde ich mal an dieser Abfrage rumfeilen. Optimiert ist das 100% *nicht*, denn mit dem Einsatz (redundanter) Zwischenergebnisse (z.B. Monatssummen o.ä.) würde man das in ein paar ms hinbekommen. Und falls die 15 Sek dafür benötigt werden, Hunderttausende von Datensätzen in die Applikation tu schaufeln, ist das auch nicht der richtige Weg.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:18 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz