AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Delphi Daten sammeln und in MS SQL-Datenbank hinzufügen???
Thema durchsuchen
Ansicht
Themen-Optionen

Daten sammeln und in MS SQL-Datenbank hinzufügen???

Ein Thema von romber · begonnen am 24. Jul 2009 · letzter Beitrag vom 25. Jul 2009
Antwort Antwort
romber

Registriert seit: 15. Apr 2004
Ort: Köln
1.166 Beiträge
 
Delphi 10 Seattle Professional
 
#1

Daten sammeln und in MS SQL-Datenbank hinzufügen???

  Alt 24. Jul 2009, 16:24
Datenbank: MS SQL Server • Version: 2008 • Zugriff über: ADO
Hallo!

Ich habe in meinem Programm mehrere Threads, die permanent laufen und XML-Daten liefern. Diese Daten muss ich einer MS SQL-Datenbank hinzufügen. Da es sich beim Datenbankserver um einen Remoteserver handelt und das direkte Hinzufügen im selben Thread desen Ablauf verzögern könnte (was ich in meinem Fall unbedingt vermeiden muss), habe ich einen anderen Thread erstellt, der die Daten einsammelt und der DB hinzufügt. Dafür habe ich zusätzlich noch eine TStringList erstellt, in der die für DB bestimmte Daten landen. Alle Threads fügen die XML-Daten dieser TStringList hinzu. Der DB-Thread greift immer wieder auf diese Liste zu, prüft ob neue Daten vorhanden sind und wenn was neues gibt, leitet die Daten an die DB weiter.

Problem: Einige Datensätze aus der TStringList landen doppelt in die Datenbenk, während einige gar nicht hinzufügt werden. Dabei konnte ich sicherstellen, dass es keine gleiche Daten in der TStringList gibt. Was mache ich falsch?


Liste für die Daten und CriticalSection:

Delphi-Quellcode:
...
var
  lstDBData: TStringList;
  csDBData: TCriticalSection;
So werden die Daten in die Liste hinzufügt:

Delphi-Quellcode:
...
  csDBData.Enter;
  try
    lstDBData.Add(XMLData);
  finally
    csDBData.Leave;
  end;
Thread, der die Daten verarbeitet:

Delphi-Quellcode:
type
  TAddDataToDB = class(TThread)
  constructor Create(CreateSuspended: Boolean; AAllowUpdate: Boolean);
  private
    AllowUpdate: Boolean;
  protected
    procedure Execute; override;
end;

constructor TAddDataToDB.Create(CreateSuspended: Boolean; AAllowUpdate: Boolean);
begin
  inherited Create(CreateSuspended);
  FreeOnTerminate := true;
  AllowUpdate := AAllowUpdate;
end;

procedure TAddDataToDB.Execute;
var
  ADO: TADOTable;
  XMLDoc: IXMLDocument;
  XMLRoot: IXMLNode;
begin
  CoInitialize(nil);

  ADO := TADOTable.Create(nil);
  ADO.ConnectionString := 'Provider=SQLOLEDB.1;Password=' + DB_PASSWORD + ';' +
                          'Persist Security Info=True;User ID=' + DB_USERNAME + ';' +
                          'Initial Catalog=' + DB_NAME + ';' +
                          'Data Source=' + DB_HOST;
  ADO.TableName := DB_TABLE;

  while not Terminated do
  begin
    if lstDBData.Count > 0 then
    begin
      ADO.Active := true;
      repeat
        if Length(lstDBData.Strings[0]) > 0 then
        begin
          //Hier wird XML analysieret, zerteilt und in der DB hinzufügt
        end;
        //Verarbeite Daten aus der Liste entfernen
        csDBData.Enter;
        try
          lstDBData.Delete(0);
        finally
          csDBData.Leave;
        end;
      until lstDBData.Count = 0;
      ADO.Active := false;
    end;
    Sleep(10);
  end;

  ADO.Free;
end;
  Mit Zitat antworten Zitat
dmagin

Registriert seit: 17. Jan 2003
Ort: Frankfurt
33 Beiträge
 
#2

Re: Daten sammeln und in MS SQL-Datenbank hinzufügen???

  Alt 25. Jul 2009, 10:29
hallo romber,

hast du auch sichergestellt, mit einer critical section, wenn die daten an den mssql server ge-insert-ed werden, das kein anderer die stringlist manipulieren kann. es könnte ja sein das du den insert sql mit params erstellst. genau in der zeit schiebt ein anderer thread ein neues elemnt in die liste. somit würde es erklären das dir elemente verloren gehen. auch die doppelten könnte man produzieren in dem erstmal das neue element in die db gebracht wird und nun ein neues kommt und der insert thread loslegt aber der neue eintrag noch nicht im stringlist ist da er gerade noch im reinschreiben ist.

ich vermute du hast nur eine critical section beim add in die stringlist. jedoch du musst auch beim löschen und herauslesen eine critical section einbauen. am besten benutzt du erstmal die gleiche damit alles erstmal serialisiert ist. dann müsste es laufen.

jedoch würde ich das problem etwas anders lösen.

die thread zum einsammeln kannst du lassen. diese können es auch in ein TStrings(list) reinpusten. jedoch würde ich dann auf den event itemsadd erweitern und dort den string mit übergeben. in diesem event wird dann der insert in die mssql server db ausgeführt.

beim löschen des inhaltes musst du aber auch wieder die critical section nutzen.

also summary:

bei jeder manipulation deiner TStriglist solltest du CriticalSection sauber erstellen und verlassen.

gruss daniel m
Daniel Magin
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#3

Re: Daten sammeln und in MS SQL-Datenbank hinzufügen???

  Alt 25. Jul 2009, 12:05
Anfügen und 'Nächsten Job holen' müssen geschützt werden. Am Besten Du spendierst deinem Thread zwei Methoden:
Delphi-Quellcode:
Type
  TDBThread ...
  Private
    FCS : TCriticalSection;
    Function GetNextJob :String;
  Public
    Procedure AddJob (Const aJob : String;
...
End;

Function TDBThread.GetNextJob :String;
Begin
  fCS.Enter;
  Try
    If fJobList.Count>0 Then Begin
      Result := fJobList[0];
      fJobList.Delete(0)
    End
    Else
      Result := '';
  Finally
     fCS.Lave;
  End
End;

Procedure TDBThread.AddJob (Const aJob : String;

Begin
  fCS.Enter;
  Try
    fJobList.Add(aJob);
// Ich signalisiere hier der Execute-Methode per
     Release (fDataAvailSemaphore, 1, nil);
// das ein Job zur Verarbeitung bereit steht.
// Die Semaphore wird mit
// fDataAvailSemaphore := CreateSemaphore (nil,0,maxint,nil);
// im Konstruktor initialisiert
  Finally
     fCS.Lave;
  End
End;

Procedure TDBThread.Execute;
Begin
  CoInitialize();
  // Create ADO-Connection
  While not Terminated do Begin
    WaitForSingleObject (fDataAvailSemaphore , INFINITE);
    If Not Terminated Then
       ExecuteJob (GetNextJob);
    End;
  CoUninitialize();
End;
Das klassische Designpattern eines Workerthreads.
Hier wird ein Workerthreadpool vorgestellt, an dem man recht gut studieren kann, wie das mit der Synchronisation von Threads funktioniert.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
generic

Registriert seit: 24. Mär 2004
Ort: bei Hannover
2.416 Beiträge
 
Delphi XE5 Professional
 
#4

Re: Daten sammeln und in MS SQL-Datenbank hinzufügen???

  Alt 25. Jul 2009, 12:10
Ich meine mich zu erinnern, dass Bernd Ua mal berichtet hat, dass die TADO* Komponenten nicht Multithreading fähig sind.
Vielleicht forscht du mal in diese Richtung.

Aber sicher bin ich mir nicht.
Coding BOTT - Video Tutorials rund um das Programmieren - https://www.youtube.com/@codingbott
  Mit Zitat antworten Zitat
romber

Registriert seit: 15. Apr 2004
Ort: Köln
1.166 Beiträge
 
Delphi 10 Seattle Professional
 
#5

Re: Daten sammeln und in MS SQL-Datenbank hinzufügen???

  Alt 25. Jul 2009, 14:06
Vielen Dank für Eure Beiträge!

Ich konnte das Problem inzwischen lösen, es war ein Fehler in der Funktion für die XML-Analyse. Wegen fehlerhaftger Verarbeitung von Exception wurde der genze Thread-Ablauf durcheinander. Um das Ganze dann noch sicherer zu machen, habe ich auch die hilfreichen Vorschläge von dmagin und alzaimar umgesetzt.

Zitat von dmagin:
...ich vermute du hast nur eine critical section beim add in die stringlist. jedoch du musst auch beim löschen und herauslesen eine critical section einbauen. am besten benutzt du erstmal die gleiche damit alles erstmal serialisiert ist. dann müsste es laufen.
Ich habe Critical Section für das Hibzufügen und Löschen benutzt. Jetzt habe ich noch die Critical Section für Auslesen der Daten eingebaut. Schaden kann es ja nicht.

Besten Dank an alzaimar für die Beispielcode und den Link zum Tutorial!
  Mit Zitat antworten Zitat
Antwort Antwort


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 05:01 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