Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Werte aus Liste in Datenbank schreiben, Netzunterbrechung abfangen (https://www.delphipraxis.net/193858-werte-aus-liste-datenbank-schreiben-netzunterbrechung-abfangen.html)

norwegen60 16. Sep 2017 09:34

Datenbank: MsSQL • Version: 2008 • Zugriff über: UniDac

Werte aus Liste in Datenbank schreiben, Netzunterbrechung abfangen
 
Hallo zusammen,

ich möchte in einem Thread eine TObjectlist in eine MsSQL-Datenbank schreiben.

Folgende Voraussetzungen sind vorhanden:
  • Die Liste wird während eines Messzyklus mit 10 Werten/Sekunde ergänzt
  • Die Liste ist eine Threadsave Kopie der eigentlichen Messliste
  • In der Liste sind immer nur die Werte, die noch nicht in DB gesichert wurden
  • Im Normalfall reicht Zeit aus um Daten immer gleich in DB zu schreiben

Jetzt soll aber zusätzlich sichergestellt werden, dass Daten auch dann weggeschrieben werden, wenn die Datenbankverbindung Unterbrechungen aufweist. Natürlich erst dann, wenn Verbindung wieder da.

Hier mein bisheriger Code.
Delphi-Quellcode:
procedure TThrSaveCalForce.Execute;
var
  lstCopy, lstTmp: TList;
  i, iLast:   Integer;
  Values:         TCalForce;

begin
  inherited;

  FStatus := FormatDateTime('ss.zzz', now) + ' Execute Start';
  Synchronize(syncStatusEvent);
  CoInitialize(nil);

  iLast := 0;
  lstCopy := TList.Create;
  dbQuery.Close;

  try
    while not (Terminated) do
    begin

      // Noch nicht bearbeitete Daten in Temporäre Liste kopieren
      try
        System.TMonitor.Enter(lstCalForceProc);
        Values := TCalForce.Create;
        for i := iLast to lstCalForceProc.Count - 1 do
        begin
          Values := lstCalForceProc.Items[i];
          lstCopy.Add(Values);
        end;
        iLast := i + 1;
      finally
        System.TMonitor.Exit(lstCalForceProc);
      end;

      if lstCopy.Count > 0 then
      begin
        // Kopierte Daten abhandeln (z.B. in DB speichern) und Liste wieder löschen
        try
          dbQuery.Open;

          if dbQuery.Active then
          begin
            while lstCopy.Count > 0 do
            begin
              Values := lstCopy.Items[0];

              if (Values.Art <> '') then
              begin
                dbQuery.Insert;
                dbQuery.FieldByName('CalReportID').Value := FReportID;
                dbQuery.FieldByName('Fact').Value := Values.Fact;
                dbQuery.FieldByName('FTarget').Value := Values.Ftarget;
                dbQuery.FieldByName('Art').Value := Values.Art;
                dbQuery.FieldByName('Temperatur').Value := Values.Temperatur;
                dbQuery.FieldByName('Humidity').Value := Values.Humidity;
                dbQuery.FieldByName('ServOrt').Value := FServOrt;
                dbQuery.FieldByName('ErstUserID').Value := FUserID;
                dbQuery.FieldByName('ErstDat').Value := Values.ErstDat;
                dbQuery.Post;
                FStatus := format('RepID = %d, Force = %6.2fN, Temp = %5.2f°C', [FReportID, Values.Fact, Values.Temperatur]);
                Synchronize(syncStatusEvent);
                OutputDebugString(pChar(FStatus));
              end;
              lstCopy.Delete(0); // gepeicherten Satz in lstCopy löschen
            end;
          end;
        finally
          dbQuery.Close;
        end;
      end;
      Sleep(100);
    end;
  finally
    lstCopy.Free;
  end;
  IsRunning := false;
end;
Meine Fragen:
  • Wie stelle ich schnellstmöglich fest, ob eine Verbindung besteht?
  • Bietet ein Insert direkt per "INSERT INTO TabName VALUES (FReportID, Values.Fact, ...)" Vorteile?
  • Wenn ja, bietet es Vorteile wenn ich alle Werte der Liste in ein Insert packe (Values (ListenWerte1), (ListenWerte2) ...). Unter Beachtung der maximal zulässigen Anzahl (1000)?
  • Muss nach einem Unterbruch die Connection manuell geöffnet werden oder öfnnet die sich automatisch mit dem dbQuery.Open?

Ich könnte das jetzt ausprobieren, aber meine Erfahrung ist, dass manches beim Probieren funktioniert, aber trotzdem nicht sauber ist und irgendwann schief geht. Deshalb wäre ich für Ratschläge dankbar

Grüße
Gerd

jobo 16. Sep 2017 13:36

AW: Werte aus Liste in Datenbank schreiben, Netzunterbrechung abfangen
 
Es spricht nichts gegen ein Insert Statement, im Gegenteil, besonders nicht in einer geschützen Umgebung (Injektion).
Ggf. kann man (sehr) viele Statements in eine Datei packen und als Script einfügen.
Das ginge auch sehr problemlos bei Offline:
Dateien auf den Server übertragen (wann immer es geht)
Dateien per Script in die DB laden, wenn immer welche da sind.
Das kann man ggf so gestalten, dass mehrere Insert prozesse arbeiten (können), wenn mal Stau war. Aber je nach Lockfähigkeit der DB (hier gleich Version von mssql) ist das vielleicht auch problematisch mit Parallelbetrieb.

Mehre Statements in einem Query funktionieren mit den meisten Komponenten dagegen nicht.

Bernhard Geyer 16. Sep 2017 14:27

AW: Werte aus Liste in Datenbank schreiben, Netzunterbrechung abfangen
 
Du kannst deine Lösung stark beschleunigen wenn du mehre Inserts gleichzeitig abschickst.

INSERT INTO Tab1(Feld1, Feld2, Feld3)
VALUES('A1', 'B1', 'C1'), ('A1', 'B2', 'C2'), (...), (...)...

Das dann alles noch schick mit Parameter und Prepared Statements "geschmückt" und deine Anwendung ist um einiges schneller als wenn du die Datensätze versuchst einzeln in die DB zu bringen.

norwegen60 16. Sep 2017 20:43

AW: Werte aus Liste in Datenbank schreiben, Netzunterbrechung abfangen
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1381348)
INSERT INTO Tab1(Feld1, Feld2, Feld3)
VALUES('A1', 'B1', 'C1'), ('A1', 'B2', 'C2'), (...), (...)..

Das war, was ich mit
Zitat:

wenn ich alle Werte der Liste in ein Insert packe (Values (ListenWerte1), (ListenWerte2) ...).
gemeint habe. Ich muss aber dazu sagen, dass im Normalfall jeder Datensatz gesendet werden kann bevor der nächste anfällt. D.h. bei stabiler Verbindung enthält die Liste meist nur einen Satz.

Mein Hauptproblem aber ist:
Wie stelle ich fest ob die Daten erfolgreich geschrieben wurden (und ich sie in der Lise löschen kann) oder ob die Datenbankverbindung unterbrochen ist und ich den Insert wiederholen muss? Ist da der Try ... Except der richtige Weg?


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:51 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-2025 by Thomas Breitkreuz