AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Delphi SQL Query in Thread wie Datenrückgabe realisieren

SQL Query in Thread wie Datenrückgabe realisieren

Ein Thema von stOrM · begonnen am 11. Okt 2016 · letzter Beitrag vom 14. Okt 2016
Antwort Antwort
Seite 1 von 3  1 23   
Benutzerbild von stOrM
stOrM

Registriert seit: 7. Jun 2003
Ort: Mülheim an der Ruhr
434 Beiträge
 
Delphi 10.3 Rio
 
#1

SQL Query in Thread wie Datenrückgabe realisieren

  Alt 11. Okt 2016, 13:34
Datenbank: MySQL • Version: 5.7.11 • Zugriff über: UniDac
Moin,
ich denke das Thema ist schon immer wieder mal behandelt worden nur irgendwie nicht so wie ich es gerade brauche.
Es geht darum, dass ich im Moment versuche sämtliche Query's in einem Thread auszulagern, da mir die Programmoberfläche zu oft kurze Zeit einfriert. Abgesehen davon dachte ich mir, dass es ggf. nicht die schlechteste Wahl ist, die eigentlichen Daten irgendwo zwischen zu speichern und nicht unmittelbar an die Oberfläche zu hängen, so dass ich eventuell, sollte sich die Oberfläche mal ändern, ich nicht an bestimmte Komponenten gebunden bin.

Jetzt stellt sich aber die Frage wie gebe ich die Daten aus dem separaten Thread zurück an den Main Thread.
Ich beschreibe mal grob was ich gerade gemacht habe:

Komponenten die benutzt werden:

Unidac
DxGrid


1. Separaten Thread angelegt.
Dem Thread übergebe ich im Create als Parameter den SQL Query welcher ausgeführt werden soll.
Des weiteren werden hier alle benötigten Komponenten erstellt: UniConnection, UniProvider, UniQuery.

2. Im Execute des Threads wird das Uniquery mit Execute gestartet, welches dann mit den Daten die zurück kommen gefüllt wird, sofern der SQL Query erfolgreich ausgeführt werden konnte.

Tja und nun gehts los, wie übergebe ich die Daten jetzt an ein Dataset im Main Thread?

Genau hier hakt es, da ich ja nicht direkt auf Komponenten im Main Thread zugreifen darf (max. über Syncronize oder Messages), sollte ich jetzt z.B. eine Liste oder Collection erstellen, welche die Daten aufnimmt und diese dann an den Main Thread übergeben oder welche Möglichkeiten habe ich?

Die Idee war eigentlich folgende mit z.B. der TCollection.
Wenn diese die Felddefinitionen der Tabelle(Feldname, Type, Größe) sowie die Daten darin enthält, könnte ich z.B. diese Daten direkt in der Collection verwalten (Daten löschen, anlegen usw. und damit dann ein z.B. ein TSimleDataset füllen und an ein DBGid oder CXGrid übergeben) danach wird halt ein SQL Query an den SQL Server gesendet mit dem was gerade passiert ist (löschen, anlegen update usw.)

Macht man das so, oder gibt es da bessere oder schnellere Lösungen, wie macht Ihr das?
  Mit Zitat antworten Zitat
Benutzerbild von MyRealName
MyRealName

Registriert seit: 19. Okt 2003
Ort: Heilbronn
673 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: SQL Query in Thread wie Datenrückgabe realisieren

  Alt 11. Okt 2016, 15:10
Wenn Du unidac nutzt, hast die die VirtualTable Komponente dabei, die ist mit nichts verbunden, sollte also Threadsafe sein.
Nach dem Threadstart aber noch vor dem Resume gibst du dem Thread object eine TVirtualTable mit und nach dem Query macht du ein

VirtualTable1.Assign(UniQuery1);

und dann sendest du deinem Mainthread eine message, dass die daten da sind und beendest den thread. Stell aber sicher, dass die virtualtable nicht genutzt wird, nur vor dem Thread.Resume ud wenn die Nachricht reinkam, dass die daten da sind.

Helge

Edit: da fällt mir ein, da Du ja dxgrid nutzt, schau dir mal den Servermode an, den gibt es auch für unidac, der lädt nur, was gerade an daten gebraucht wird um das grid zu füllen. Dadurch kannst du 1 mio datensätze haben, der lädt in 1 sekunde ohne probleme. auch beim scrollen wird da nur geladen, was gerade benötigt wird.

Geändert von MyRealName (11. Okt 2016 um 15:12 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von stOrM
stOrM

Registriert seit: 7. Jun 2003
Ort: Mülheim an der Ruhr
434 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: SQL Query in Thread wie Datenrückgabe realisieren

  Alt 11. Okt 2016, 18:21
Wenn Du unidac nutzt, hast die die VirtualTable Komponente dabei, die ist mit nichts verbunden, sollte also Threadsafe sein.
Nach dem Threadstart aber noch vor dem Resume gibst du dem Thread object eine TVirtualTable mit und nach dem Query macht du ein

VirtualTable1.Assign(UniQuery1);

und dann sendest du deinem Mainthread eine message, dass die daten da sind und beendest den thread. Stell aber sicher, dass die virtualtable nicht genutzt wird, nur vor dem Thread.Resume ud wenn die Nachricht reinkam, dass die daten da sind.

Helge

Edit: da fällt mir ein, da Du ja dxgrid nutzt, schau dir mal den Servermode an, den gibt es auch für unidac, der lädt nur, was gerade an daten gebraucht wird um das grid zu füllen. Dadurch kannst du 1 mio datensätze haben, der lädt in 1 sekunde ohne probleme. auch beim scrollen wird da nur geladen, was gerade benötigt wird.
Irgendwie hab ich gerade eine Denkblockade:

1. Ich soll dem Thread eine Virtualtable mitgeben, ok kann ich machen.
2. Dann soll ich später VirtualTable1.Assign(UniQuery1); ausführen. Woher soll Query1 jetzt gekommen sein, den gibt es nicht, also noch nicht.
Der Main Thread besitzt nur das Grid sonst nichts.

Alles andere wird ja im separaten Thread ausgeführt (also gibt es dort auch nur das Query.

Das mit dem Servermode klingt interessant, aber ist jetzt im Moment noch nicht mein Problem, behalte ich aber mal im Hinterkopf, zur Zeit gehts es nur um die Auslagerung der Querys in einem eigenen Thread und vor allem um die Rückgabe.
  Mit Zitat antworten Zitat
Benutzerbild von MyRealName
MyRealName

Registriert seit: 19. Okt 2003
Ort: Heilbronn
673 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: SQL Query in Thread wie Datenrückgabe realisieren

  Alt 11. Okt 2016, 18:39
OK, erstmal zum grundsatz : Ich nehme mal an, dass Du die Queries in einen Thread auslagern willst, weil sonst deine app zulange nicht reagiert, oder ?
Ich nehme mal an, dass es so ist ...

Der Servermode ist ja deswegen interessant, weil er halt die ergebnislisten so klein hält, dass du keinen thread brauchst, somit wäre dein Problem an der Stelle schon gelöst.

Aber gehen wir doch auf den Thread ein :

Komponenten die du brauchst sind :

TVirtualTable (VT) (Mainthread)
TUniConnection, TUniQuery (UniQuery1) (add. Thread)

Du erstellst den Thread suspended, gibst ihm die VT und startest den Thread. Der erzeugt die connection und die uniquery componenten, fährt die Abfrage und macht dann das assign zur VirtualTable, damit die VT die Daten hat. Dann schliesst das Query und die Verbindung und sendest deinem Mainthread die NAchricht, dass die Daten fertig sein und der zerstört den thread oder lässt den thread sich zerstören, aber nicht die VT, die kannst Du gleich als Dataset für das grid dann nutzen, aber erst der Datasource zuweisen, wenn der Thread fertig ist, sonst versicht das grid die schon zu lesen während du sie noch befüllst.

Verbesserung : Schau dass du vllt nur 100 datensätze erstmal liest um im Grid schon was anzuzeigen und im thread die anderen nachholst. IN firebird geht das mit

SELECT FIRST 100 (für die ersten 100)
SELECT FIRST 100 SKIP 100 (für die nächsten 100)

Bei MySQL kenn ich mich aber ned so aus

Ich hoffe, das hilft dir weiter
  Mit Zitat antworten Zitat
Benutzerbild von stOrM
stOrM

Registriert seit: 7. Jun 2003
Ort: Mülheim an der Ruhr
434 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: SQL Query in Thread wie Datenrückgabe realisieren

  Alt 11. Okt 2016, 21:55
OK, erstmal zum grundsatz : Ich nehme mal an, dass Du die Queries in einen Thread auslagern willst, weil sonst deine app zulange nicht reagiert, oder ?
Ich nehme mal an, dass es so ist ...

Der Servermode ist ja deswegen interessant, weil er halt die ergebnislisten so klein hält, dass du keinen thread brauchst, somit wäre dein Problem an der Stelle schon gelöst.

Aber gehen wir doch auf den Thread ein :

Komponenten die du brauchst sind :

TVirtualTable (VT) (Mainthread)
TUniConnection, TUniQuery (UniQuery1) (add. Thread)

Du erstellst den Thread suspended, gibst ihm die VT und startest den Thread. Der erzeugt die connection und die uniquery componenten, fährt die Abfrage und macht dann das assign zur VirtualTable, damit die VT die Daten hat. Dann schliesst das Query und die Verbindung und sendest deinem Mainthread die NAchricht, dass die Daten fertig sein und der zerstört den thread oder lässt den thread sich zerstören, aber nicht die VT, die kannst Du gleich als Dataset für das grid dann nutzen, aber erst der Datasource zuweisen, wenn der Thread fertig ist, sonst versicht das grid die schon zu lesen während du sie noch befüllst.

Verbesserung : Schau dass du vllt nur 100 datensätze erstmal liest um im Grid schon was anzuzeigen und im thread die anderen nachholst. IN firebird geht das mit

SELECT FIRST 100 (für die ersten 100)
SELECT FIRST 100 SKIP 100 (für die nächsten 100)

Bei MySQL kenn ich mich aber ned so aus

Ich hoffe, das hilft dir weiter
Deine Annahme ist völlig korrekt.
Ich bin im Moment nicht zuhause, aber ich werde das Morgen mal versuchen umzusetzen und melde mich dann mal mit deinem kompletten kleinen Projekt zurück, dass ist viel leicht sinnvoller als wenn ich das alles hypothetisch erklären bzw. hat vielleicht jemand anderes ein ähnliches Problem und lernt dann aus meinen Fehlern oder der Umsetzung wie man es machen kann.
Bis dahin erstmal vielen Dank für die nützlichen Tips!
  Mit Zitat antworten Zitat
Benutzerbild von stOrM
stOrM

Registriert seit: 7. Jun 2003
Ort: Mülheim an der Ruhr
434 Beiträge
 
Delphi 10.3 Rio
 
#6

AW: SQL Query in Thread wie Datenrückgabe realisieren

  Alt 13. Okt 2016, 12:17
Ok also wie gesagt hab ich mich mal an den Thread gewagt und die Rückgabe in eine VirtualTable gelegt.

1. Problem, ich habe zur schnellen Überprüfung einfach ein DBGrid benutzt, manchmal jedoch nicht immer kommt es zu der Meldung: Canvas erlaubt kein zeichnen, gestoppt wird in VCL.Graphics Zeile 4197 Da weiss ich gerade auch nicht warum der Fehler auftritt.

2. Ein weiteres Problem zu dem es kommen kann und da wird es richtig wild, (Ich hab zum Test das Create, Start des Thread auf einen Button gelegt, wenn dieser aber zu schnell hintereinander geklickt wird haut es mir ziemlich viele Exceptions um die Ohren, angefangen von Blob Fehler bis hin zu (Gitternetz irgendwas, müsste ich noch mal genau nachsehen.)

Gut das kann ich schnell umgehen in dem ich einfach den Button so lange sperre wie der separate Thread läuft. In der späteren Hauptanwendung benutze ich ein PageControl, welches beim Seitenwechsel quasi den Thread starten soll um die GUI (Grid und weitere DBControls) mit den Werten zu füllen, da müsste ich mal sehen wie ich das unterbinde das die Seiten zu schnell gewechselt werden.

Dann schmeiss ich mal den Code hier rein und hoffe mir kann da jemand auf die Sprünge helfen bezüglich obiger Probleme (Ich geh einfach mal davon aus, mein Thread hat einen Designfehler oder die Hauptanwendung oder beides )

Die Anwendung:

Delphi-Quellcode:
unit fmView;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Vcl.StdCtrls, Vcl.ComCtrls,
  MemDS, VirtualTable, DBAccess, Uni, Vcl.Grids, Vcl.DBGrids,

  QueryThread;

type
  TView = class(TForm)
    DBGrid1: TDBGrid;
    UniDataSource1: TUniDataSource;
    VirtualTable1: TVirtualTable;
    StatusBar1: TStatusBar;
    MSGLog: TMemo;
    Label1: TLabel;
    btnStart: TButton;
    edtConStr: TEdit;
    edtSqlTxt: TEdit;
    QrPB: TProgressBar;
    procedure btnStartClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private-Deklarationen }
    FSQLThrd: TSqlQueryThrd;
    procedure OnThreadStatusMsg(
      const ThreadStatusMsgPtr: PThreadStatusdMsg);

    procedure OnThreadQueryStarted(
      const ThreadQueryStartedMsgPtr: PThreadQueryStartMsg);

    procedure OnThreadQueryDone(
      const ThreadQueryDoneMsgPtr: PThreadQueryDoneMsg);

    procedure OnThreadQueryRecCount(
      const ThreadQueryRecCountMsgPtr: PThreadQueryRecCountMsg);
  public
    { Public-Deklarationen }
  protected
    procedure WndProc(var AMsg: TMessage); override;
  end;

var
  View: TView;

implementation

{$R *.dfm}

procedure TView.btnStartClick(Sender: TObject);
begin
  // I know this will leak at the moment!
  FSQLThrd := TSqlQueryThrd.Create(self.Handle, edtConStr.Text, edtSqlTxt.Text,
    VirtualTable1);
  try
    FSQLThrd.FreeOnTerminate := false;
    FSQLThrd.Start;
  except
  on E: Exception do
    MSGLog.Lines.Text := E.Message;
  end;
end;

procedure TView.FormDestroy(Sender: TObject);
begin
  if assigned(FSQLThrd) then
  begin
    FSQLThrd.Terminate;
    FSQLThrd.WaitFor;
    FSQLThrd.Free;
  end;
end;

procedure TView.OnThreadQueryStarted(
  const ThreadQueryStartedMsgPtr: PThreadQueryStartMsg);
begin
  case ThreadQueryStartedMsgPtr^.Running of
   true: QrPB.State := pbsNormal;
   false: QrPB.State := pbsPaused;
  end;
  Dispose(ThreadQueryStartedMsgPtr);
end;

procedure TView.OnThreadQueryDone(
  const ThreadQueryDoneMsgPtr: PThreadQueryDoneMsg);
begin
  case ThreadQueryDoneMsgPtr^.Done of
   true:
   begin
     QrPB.State := pbsPaused;
     try
       UniDataSource1.DataSet.DisableControls;
       UniDataSource1.DataSet := VirtualTable1;
       // exception
       // VCL.Graphics line 4197
       // EInvalidOperation: Canvas erlaubt kein zeichnen!
       DBGrid1.DataSource := UniDataSource1;
     finally
       UniDataSource1.DataSet.EnableControls;
     end;
   end;
   false: QrPB.State := pbsNormal;
  end;
   Dispose(ThreadQueryDoneMsgPtr);
end;

procedure TView.OnThreadStatusMsg(
  const ThreadStatusMsgPtr: PThreadStatusdMsg);
begin
  MSGLog.Lines.Add( string.Format('%s %s %s',
    [
     ThreadStatusMsgPtr^.ExecTime,
     ThreadStatusMsgPtr^.MessageStr,
     ThreadStatusMsgPtr^.SQLStr
    ]));
  Dispose(ThreadStatusMsgPtr);
end;

procedure TView.OnThreadQueryRecCount(
  const ThreadQueryRecCountMsgPtr: PThreadQueryRecCountMsg);
begin
  Statusbar1.Panels[0].Text := string.Format('RecCount: %s' ,
    [IntToStr(ThreadQueryRecCountMsgPtr^.ICount)]);
  Dispose(ThreadQueryRecCountMsgPtr);
end;

procedure TView.WndProc(var AMsg: TMessage);
begin
  with AMsg do
  begin
    case Msg of
      TS_THREAD_STATUS_AVAILABLE: OnThreadStatusMsg(
          PThreadStatusdMsg(WParam));

      TS_THREAD_QUERY_STARTED: OnThreadQueryStarted(
          PThreadQueryStartMsg(WParam));

      TS_THREAD_QUERY_DONE: OnThreadQueryDone(
          PThreadQueryDoneMsg(WParam));

      TS_THREAD_QUERY_COUNT: OnThreadQueryRecCount(
          PThreadQueryRecCountMsg(WParam));
    end;
  end;
  inherited;
end;

end.
Der Thread für die SQL Querys:

Delphi-Quellcode:
unit QueryThread;

interface

uses
  System.Classes,
  System.SysUtils,
  Winapi.Windows,
  Winapi.Messages,
  UniProvider,
  MySQLUniProvider,
  Data.DB,
  DBAccess,
  Uni,
  MemDS,
  MemData,
  VirtualTable;

// messages to be send to the main thread
const
  TS_THREAD_STATUS_AVAILABLE = WM_USER + 1;
  TS_THREAD_QUERY_STARTED = WM_USER +2;
  TS_THREAD_QUERY_DONE = WM_USER +3;
  TS_THREAD_QUERY_COUNT = WM_USER +4;

type
  TThreadStatusMsg = record
    MessageStr: string;
    SQLStr: string;
    ExecTime: String;
  end;
  PThreadStatusdMsg = ^TThreadStatusMsg;

  TThreadQueryStartMsg = record
    Running: Boolean;
  end;
  PThreadQueryStartMsg = ^TThreadQueryStartMsg;

  TThreadQueryDoneMsg = record
    Done: Boolean;
  end;
  PThreadQueryDoneMsg = ^TThreadQueryDoneMsg;

  TThreadQueryRecCountMsg = record
    ICount: Int64;
  end;
  PThreadQueryRecCountMsg = ^TThreadQueryRecCountMsg;

type
  TSqlQueryThrd = class(TThread)
  protected
    procedure Execute; override;
    procedure OnAfterFetchEvent(DataSet: TCustomDADataSet);
    procedure OnAfterOpen(DataSet: TDataSet);
  private
    FMainHandle: THandle;
    FSQLText: string;
    fStatusText: string;
    FUniDacConnection: TUniConnection;
    FUniDacSQLQuery: TUniQuery;
    FVirtualTable: TVirtualTable;

    ThreadStatusMsgPtr: PThreadStatusdMsg;
    ThreadQueryStartedMsgPtr: PThreadQueryStartMsg;
    ThreadQueryDoneMsgPtr: PThreadQueryDoneMsg;
    ThreadQueryRecCountMsgPtr: PThreadQueryRecCountMsg;

    function GetLongTime(aTime: TDatetime) : string;
  public
    constructor Create(aMainHandle: THandle; aConnectionStr: string;
      aSQL: string; aVTable: TVirtualTable); overload;
    destructor Destroy; override;

  end;

implementation

{ TSqlQueryThrd }

constructor TSqlQueryThrd.Create(aMainHandle: THandle;
  aConnectionStr, aSQL: string; aVTable: TVirtualTable);
begin
  inherited Create(True);
  
  // main thread handle
  FMainHandle := aMainHandle;

  FUniDacConnection := TUniConnection.Create(nil);
  FUniDacConnection.ProviderName := 'MySQL';
  FUniDacConnection.ConnectString := aConnectionStr;
  Assert(aConnectionStr <> '', 'Connection-String can not be empty!');

  // test if connection is successful otherwise goodbye
  try
    try
      FUniDacConnection.Connect;
    except
      terminate;
    end;
  finally
    // can be disconnected the unidac query established a connection by itself if needed
    FUniDacConnection.Disconnect;
  end;

  FSQLText := aSQL;
  Assert(FSQLText <> '', 'SQL-Text can not be empty!');

  FUniDacSQLQuery := TUniQuery.Create(nil);
  FUniDacSQLQuery.Connection := FUniDacConnection;
  FUniDacSQLQuery.FetchingAll;
  FUniDacSQLQuery.AfterFetch := OnAfterFetchEvent;
  FUniDacSQLQuery.AfterOpen := OnAfterOpen;
  FUniDacSQLQuery.SQL.Clear;
  FVirtualTable := aVTable;
end;

destructor TSqlQueryThrd.Destroy;
begin
  if FUniDacConnection.Connected then
    FUniDacConnection.Disconnect;
  FUniDacConnection.Free;
  FUniDacSQLQuery.Free;
  inherited Destroy;
end;

procedure TSqlQueryThrd.Execute;
begin
  NameThreadForDebugging('StormThread');

  FUniDacSQLQuery.SQL.Text := FSQLText;

  // send the main thread some messages...
  New(ThreadQueryStartedMsgPtr);
  ThreadQueryStartedMsgPtr^.Running := True;
  if not(PostMessage(FMainHandle, TS_THREAD_QUERY_STARTED,
    integer(ThreadQueryStartedMsgPtr), 0)) then
  begin
    Dispose(ThreadQueryStartedMsgPtr);
    terminate;
  end;

  New(ThreadStatusMsgPtr);
  ThreadStatusMsgPtr^.MessageStr := 'Status: Query started';
  ThreadStatusMsgPtr^.ExecTime := GetLongTime(Now);
  ThreadStatusMsgPtr^.SQLStr := '';
  if not(PostMessage(FMainHandle, TS_THREAD_STATUS_AVAILABLE,
    integer(ThreadStatusMsgPtr), 0)) then
  begin
    Dispose(ThreadStatusMsgPtr);
    terminate;
  end;

  try
    try
      FUniDacSQLQuery.Execute;

      // Must be set here otherwise the virtualtable in the main thread
      // does not contain any data!
      FVirtualTable.Assign(FUniDacSQLQuery);
    except
      FUniDacSQLQuery.Close;
      FUniDacConnection.Close;
      terminate;
    end;
  finally
    FUniDacSQLQuery.Close;
    FUniDacConnection.Disconnect;
    terminate;
  end;
end;

function TSqlQueryThrd.GetLongTime(aTime: TDatetime): string;
var
  formattedDate : string;
begin
  Result :='';
  try
    DateTimeToString(formattedDate, 'hh:nn:ss:zz', aTime);
  finally
    Result := FormattedDate;
  end;
end;

// special for unidac if that event is raised the query is done as written in the docu...
procedure TSqlQueryThrd.OnAfterFetchEvent(DataSet: TCustomDADataSet);
begin
  New(ThreadStatusMsgPtr);
  ThreadStatusMsgPtr^.MessageStr := 'Status: Query done';
  ThreadStatusMsgPtr^.ExecTime := GetLongTime(Now);
  ThreadStatusMsgPtr^.SQLStr := '// ' + FSQLText;
  if not(PostMessage(FMainHandle, TS_THREAD_STATUS_AVAILABLE,
    integer(ThreadStatusMsgPtr), 0)) then
  begin
    Dispose(ThreadStatusMsgPtr);
    terminate;
  end;

  New(ThreadQueryDoneMsgPtr);
  ThreadQueryDoneMsgPtr^.Done := True;
  if not(PostMessage(FMainHandle, TS_THREAD_QUERY_DONE,
    integer(ThreadQueryDoneMsgPtr), 0)) then
  begin
    Dispose(ThreadQueryDoneMsgPtr);
    terminate;
  end;
end;

// this event is raised when the record count is available
procedure TSqlQueryThrd.OnAfterOpen(DataSet: TDataSet);
begin
  New(ThreadQueryRecCountMsgPtr);
  ThreadQueryRecCountMsgPtr^.ICount := FUniDacSQLQuery.RecordCount;
  if not(PostMessage(FMainHandle, TS_THREAD_QUERY_COUNT,
    integer(ThreadQueryRecCountMsgPtr), 0)) then
  begin
    Dispose(ThreadQueryRecCountMsgPtr);
    terminate;
  end;
end;

end.
  Mit Zitat antworten Zitat
CarlAshnikov

Registriert seit: 18. Feb 2011
Ort: Erfurt
108 Beiträge
 
Delphi XE5 Enterprise
 
#7

AW: SQL Query in Thread wie Datenrückgabe realisieren

  Alt 13. Okt 2016, 12:50
Was mir beim ersten Drüberschauen aufgefallen ist:

Du benutzt Postmessage d.h. es wird nicht gewartet bis die Nachrichten verarbeitet sind. Kann es dadurch zu Problemen kommen weil der VCL-Thread und dein Query-Thread gleichzeitig auf Sachen zugreifen?

Du rufst häufig Terminate auf, wertest aber Terminated nicht aus. Terminate beendet den Thread nicht sofort!
Sebastian
Das kann ja wohl nicht var sein!
  Mit Zitat antworten Zitat
Benutzerbild von stOrM
stOrM

Registriert seit: 7. Jun 2003
Ort: Mülheim an der Ruhr
434 Beiträge
 
Delphi 10.3 Rio
 
#8

AW: SQL Query in Thread wie Datenrückgabe realisieren

  Alt 13. Okt 2016, 13:00
Was mir beim ersten Drüberschauen aufgefallen ist:

Du benutzt Postmessage d.h. es wird nicht gewartet bis die Nachrichten verarbeitet sind. Kann es dadurch zu Problemen kommen weil der VCL-Thread und dein Query-Thread gleichzeitig auf Sachen zugreifen?

Du rufst häufig Terminate auf, wertest aber Terminated nicht aus. Terminate beendet den Thread nicht sofort!
Ja, und eventuell. Wegen dem Postmessage war mein Gedanke, dass nicht gewartet werden soll, da ich dachte das es so ggf. wieder zum Einfrieren der GUI kommen kann, denn dann hätte ich mir den seperaten Thread komplett sparen können oder Syncronize einsetzen können.

Ich kann wie gesagt mir das Problem im Moment selbst nicht erklären. Wegen dem Terminate geb ich Dir recht, dass ist so völliger Blödsinn.

P.s. Was mir noch einfällt, eigentlich sofern ich die Doku von Unidac richtig verstanden habe, greife ich erst dann auf Sachen zu bzw. weise diese zu wenn das Query fertig ist, also nicht vorher.
Lt. Doku ist dies der Fall wenn AfterFetch eintritt, siehe Thread.

Geändert von stOrM (13. Okt 2016 um 13:03 Uhr) Grund: Tante Edit war da
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#9

AW: SQL Query in Thread wie Datenrückgabe realisieren

  Alt 13. Okt 2016, 14:28
Verstehe von dem Thema nicht wirklich was, aber was mich verwundert:

Wenn der Thread fertig ist, weist Du Datasource die VirtualTable zu und dem Grid dann DataSource.

Das kann ich nachvollziehen, allerdings hätte ich erwartet, dass vor dem Start des Thread eben gerade diese Verbindung aufgehoben wird.

Ich würd' hier also erwarten, dass nach dem ersten Threadstarten für die restliche Laufzeit des Programmes die Verbindung VirtualTable->DataSource->Grid bestehen bleibt.
Allerdings hatte ich die bisherige Anforderung so verstanden, dass eben genau das nicht der Fall sein soll.

Dashier verstehe ich nicht:
Delphi-Quellcode:
 try
    try
      FUniDacSQLQuery.Execute;

      // Must be set here otherwise the virtualtable in the main thread
      // does not contain any data!
      FVirtualTable.Assign(FUniDacSQLQuery);
    except
      FUniDacSQLQuery.Close;
      FUniDacConnection.Close;
      terminate;
    end;
Execute nimmt man bei 'ner Query doch eigentlich, wenn man keine Ergebnismenge erwartet, also bei Insert, Update ...
Müsste es bei 'nem Select noch Open heißen.
Bei 'nem Execute ist doch eigentlich auch kein Close erforderlich.
Oder ist das hier in diesem Zusammenhang anders?
  Mit Zitat antworten Zitat
Benutzerbild von stOrM
stOrM

Registriert seit: 7. Jun 2003
Ort: Mülheim an der Ruhr
434 Beiträge
 
Delphi 10.3 Rio
 
#10

AW: SQL Query in Thread wie Datenrückgabe realisieren

  Alt 13. Okt 2016, 14:36
Verstehe von dem Thema nicht wirklich was, aber was mich verwundert:

Wenn der Thread fertig ist, weist Du Datasource die VirtualTable zu und dem Grid dann DataSource.

Das kann ich nachvollziehen, allerdings hätte ich erwartet, dass vor dem Start des Thread eben gerade diese Verbindung aufgehoben wird.

Ich würd' hier also erwarten, dass nach dem ersten Threadstarten für die restliche Laufzeit des Programmes die Verbindung VirtualTable->DataSource->Grid bestehen bleibt.
Allerdings hatte ich die bisherige Anforderung so verstanden, dass eben genau das nicht der Fall sein soll.

Dashier verstehe ich nicht:
Delphi-Quellcode:
 try
    try
      FUniDacSQLQuery.Execute;

      // Must be set here otherwise the virtualtable in the main thread
      // does not contain any data!
      FVirtualTable.Assign(FUniDacSQLQuery);
    except
      FUniDacSQLQuery.Close;
      FUniDacConnection.Close;
      terminate;
    end;
Execute nimmt man bei 'ner Query doch eigentlich, wenn man keine Ergebnismenge erwartet, also bei Insert, Update ...
Müsste es bei 'nem Select noch Open heißen.
Bei 'nem Execute ist doch eigentlich auch kein Close erforderlich.
Oder ist das hier in diesem Zusammenhang anders?
Ja da hast Du recht, dass mit dem Open bzw. Execute ist mir auch gerade aufgefallen, muss in dem Fall natürlich Open lauten. Danke für den Hinweis.

Zitat:
Das kann ich nachvollziehen, allerdings hätte ich erwartet, dass vor dem Start des Thread eben gerade diese Verbindung aufgehoben wird.
Das kann sollte ich vielleicht mal testen. Zumindest wäre das sinnvoll, Beim OnCreate des Formulars ist alles noch ungebunden, aber wenn der separate Thread gestartet wurde nicht mehr, ich ändere das mal ab.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:39 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz