Einzelnen Beitrag anzeigen

hschmid67

Registriert seit: 2. Jul 2012
Ort: Weilheim i. Obb.
62 Beiträge
 
Delphi 10.4 Sydney
 
#1

DB-Abfragen in Thread - dann joinen

  Alt 28. Sep 2019, 10:01
Hallo zusammen,

ich habe schon einiges gelesen zu dem Thema, aber so ganz verstanden habe ich es wohl noch nicht. Daher wäre ich froh, wenn mir jemand zu folgendem Problem mit Wissen weiterhelfen könnte:

Ich habe ein paar Tabellen aus unterschiedlichen Datenbanken (mySQL, MSSQL, auch per REST in einem Dataset), deren Daten ich zur Auswertung und Übersicht gerne miteinander verbinden möchte (INNER oder LEFT JOIN). Das ganze geht mit UniDAC VirtualQuery ja ganz gut.

Soweit habe ich das auch schon am Laufen und es ist alles gut - bis auf die Geschwindigkeit.

Nun brauchen die Abfragen aber teilweise länger und in der Zeit steht mein Hauptthread dann und wartet - und der User sieht nichts (außer vielleicht den Warte-Cursor - oder einen entsprechenden Hinweis). Dabei hätte ich die erste Teilabfrage relativ performant und könnte also schon erstmal die Grunddaten liefern, aber solange die anderen zu verknüpfenden Daten nicht da sind, läuft erstmal nichts.

Nun wäre meine Idee, die länger laufenden Abfragen in einen Thread auszulagern und zu Beginn schon mal die ersten Daten, die schneller verfügbar sind, anzuzeigen.

Aber wie bekomme ich das dann aus den Threads wieder zurück, ohne dass ich mir auf Dauer (und vielleicht zunächst nicht sichtbar) mit der VCL Ärger einfange?

Was ich bisher gelesen habe, braucht eine Datenbankabfrage in einem zweiten Thread eine eigene DB-Verbindung.

Konkret nun meine Fragen:

Wenn ich auf dem Mainform die DB-Connections erstelle, diese dann jeweils nur in einem Thread verwende, ist das ok, oder muss ich die DB-Verbindung auch im Thread erstellen, öffnen und wieder schließen? Wenn dem so sein sollte, wie bekomme ich dann die Query mit den Daten (wenn die Verbindung wieder geschlossen ist) aus dem Thread raus?

Kann ich auf dem Mainform (oder einem entsprechenden DataModule) auch die Abfragen platzieren, die ich dann jeweils nur im Thread verwende - hmmm, dann aber doch in die VirtualQuery wieder mit einbinde (dann hätte ich sie ja doch im MailThread auch)?

Oder muss ich die DB-Verbindung im Thread erstellen und auch die Query, dann am Ende des Threads in die VirtualQuery einbinden - und wenn ich den Thread zum Auffrischen dann später mal wieder ausführen sollte, die alte Verbindung und die alte Query erst löschen, dann neu erstellen???

Ihr seht schon, ich stehe auf dem Schlauch - und weiß nicht so recht, was gut wäre und was wirklich funktioniert. Bei meiner Arbeit mit Threads bin ich schon öfter darauf gestoßen, dass es zunächst mal ganz gut funktioniert hat, aber dann doch irgendwann unfassbare Fehler aufgetreten sind, wenn es nicht richtig gemacht war.

Was ich bisher mal versucht habe - und was auch funktioniert, ist folgender Code (zwei TUniConnection, zwei TUniQuery, eine TVirtualQuery - und das Ganze mit OmniThreadLibrary). Die Verbindungen zu den Datenbanken baue ich im FormCreate auf.

Delphi-Quellcode:
procedure TForm16.btn1Click(Sender: TObject);
begin
  vqJoined.DisableControls;
  try
    vqJoined.Close;
    hsDBSetWhereMacro(qPersons, 'WHERE id < 200');
    hsDBSetWhereMacro(qProfil, 'WHERE 1 = 2');
    vqJoined.Open;
  finally
    vqJoined.EnableControls;
  end;
end;

procedure TForm16.btn2Click(Sender: TObject);
begin
  CreateTask(procedure(const mTask: IOmniTask)
    begin
      vqJoined.DisableControls;
      hsDBSetWhereMacro(qProfil, 'WHERE id < 200');
    end)
    .OnTerminated(procedure(const mTask: IOmniTaskControl)
      begin
        vqJoined.Refresh;
        vqJoined.EnableControls;
      end)
    .Unobserved
    .Run;
end;
Was meint ihr? Wie macht ihr sowas, bzw. wo seht ihr die Fallstricke? Und wie könnte ich es sicher machen?

Viele Grüße
Harald
Harald Schmid
  Mit Zitat antworten Zitat