![]() |
Datenbank: MSSQL • Version: 2014 • Zugriff über: DB Express TSQLConnection
TSQLDataSet, TSQLConnection Multithread Exception
Hallo zusammen.
ich habe eine Anwendung geschrieben in der in einem Thread Daten via TCPIP von einem Server gelesen werden und in eine MSSQL Datenbank eingegraten werden. Hierfür verwende ich TSQLDataSet, TSQLConnection Beispiel:
Delphi-Quellcode:
funktioniert auch wunderbar.
FSQLDataset.Close;
FSQLDataset.CommandText := SQLCommand; FSQLDataset.ExecSQL(true); Allerdings möchte ich jetzt im Main Thread (VCL) jetzt eine Anzahl der Datensätze aus der Tabelle ermitteln. Hierfür habe ich wieder eine TSQLDataSet, TSQLConnection Komponente verwendet. Somit eigentlich schön Threadsafe Beispiel der abfrage
Delphi-Quellcode:
und so weiter
SQLDS_Work.Close;
SQLDS_Work.CommandText := 'SELECT COUNT(WareneingangsNr) from WEP02.dbo.WareneingangsNr WHERE Aktiv = 1'; SQLDS_Work.Open; if SQLDS_Work.FieldCount > 0 then begin if SQLDS_Work.Fields[0].AsInteger > 1 then begin // Fehler weil mehrere Wareneingänge aktiv if Assigned(Logger) then begin Logger.LogErrorMessage('Es sind ' + IntToStr(SQLDS_Work.RecordCount) + ' Wareneingänge aktiv. Fehler bei Timer_Chart aufgetreten'); end; Exit; end wenn jeweils nur ein Thread läuft funktioniert es ohne Probleme. Laufen beide knallts. Aber warum? Ich baue für jeden Thread eine extra Verbindung auf. Eigentlich sollte eine MSSQL Datenbank doch so etwas können. Es werden auch keine Objekte aus dem jeweils anderen Thread verwendet. Danke für eure Hilfe |
AW: TSQLDataSet, TSQLConnection Multithread Exception
Zwei Datenverbindungen auf die gleiche Tabelle - davon ein schreibender Zugriff. Wird der lesende Zugriff da nicht ausgesperrt?
|
AW: TSQLDataSet, TSQLConnection Multithread Exception
Zitat:
|
AW: TSQLDataSet, TSQLConnection Multithread Exception
Also ich bekomme eine Exception der Klasse $C00000005 mit der Meldung '$C00000005 ACCESS_VIOLATION'
Ich denke es gibt hier verschiedene Isolation Levels ![]() Allerdings bei jeder Veränderung meinerseits, das gleiche Ergebnis |
AW: TSQLDataSet, TSQLConnection Multithread Exception
Mit solch spärlichen Informationen kann dir wahrscheinlich hier keiner helfen.
|
AW: TSQLDataSet, TSQLConnection Multithread Exception
dann wirst DU wohl oder übel doch einfach mal eine Frage stellen müssen.
Hier noch die DBXConfig.ini DriverName=MSSQL SchemaOverride=%.dbo DriverUnit=Data.DBXMSSQL DriverPackageLoader=TDBXDynalinkDriverLoader,DBXCo mmonDriver190.bpl DriverAssemblyLoader=Borland.Data.TDBXDynalinkDriv erLoader,Borland.Data.DbxCommonDriver,Version=19.0 .0.0,Culture=neutral,PublicKeyToken=91d62ebb5b0d1b 1b MetaDataPackageLoader=TDBXMsSqlMetaDataCommandFact ory,DbxMSSQLDriver190.bpl MetaDataAssemblyLoader=Borland.Data.TDBXMsSqlMetaD ataCommandFactory,Borland.Data.DbxMSSQLDriver,Vers ion=19.0.0.0,Culture=neutral,PublicKeyToken=91d62e bb5b0d1b1b LibraryName=dbxmss.dll VendorLib=sqlncli10.dll VendorLibWin64=sqlncli10.dll HostName=DE01PCSF0799\AUT_SQL_SERVER Database=WEP02 MaxBlobSize=-1 LocaleCode=0000 IsolationLevel=DirtyRead OSAuthentication=False PrepareSQL=True User_Name= Password= BlobSize=-1 ErrorResourceFile= OS Authentication=False Prepare SQL=False |
AW: TSQLDataSet, TSQLConnection Multithread Exception
Du könntest z.B. debuggen und sagen wo welche Fehlermeldung auftaucht, oder du könntest den Quellcode des Threads zeigen, wo z.B. wie synchronisiert wird. Eine Zugriffsverletzung ist meist ein Hinweis auf einen Zugriff auf ein Objekt, das bereits freigegeben wurde, dass die SQL-Statements das auslösen ist recht unwahrscheinlich.
|
AW: TSQLDataSet, TSQLConnection Multithread Exception
Na das is doch mal eine Ansage.
Mach ich doch gleich so gut ich kann. ich habe jetzt mit einem try-except endlich eine genauere Fehlerbeschreibung: 04.12.2015 11:19:27 Client : Exception = Zugriffsverletzung bei Adresse 000000000BB4768C in Modul 'dbxmss.dll'. Lesen von Adresse FFFFFFFFFFFFFFFF 04.12.2015 11:20:16 Client : Exception = Zugriffsverletzung bei Adresse 000000000BB47680 in Modul 'dbxmss.dll'. Lesen von Adresse 0000000000000082 Der Thread sieht in etwa so aus
Delphi-Quellcode:
Und Das updaten der Anzeige im Main wird von einem Timer getriggert und sieht dann so ausif DataCount > 0 then begin // Daten einlesen SendStr := 'Worksation;' + FormatDateTime('yyyy.mm.dd hh-nn-ss', now) + ';' + IntToStr(SessionID) + ';FetchDataToTransmit##'; FIdTCPClient.IOHandler.WriteLn(SendStr, nil); for j := 0 to Datacount - 1 do begin if not KommEnable then begin // Wenn der Benutzer die Kommunikation pausiert, hier warten bis es weiter geht! FIdTCPClient.Disconnect; Logged := false; break; end; for i := 0 to 21 do begin Count := FIdTCPClient.IOHandler.ReadLongInt(false); RecStr := FIdTCPClient.IOHandler.ReadString(Count, nil); Logger.LogMessage('Server : ' + RecStr); if DataExport then begin SLStr := SLStr + #9 + RecStr; end; Daten[i] := RecStr; if i = 21 then begin if not DataNotInDB then begin // doppelte Verneinung (; if Produkt_Auswerten(Daten) < 0 then begin KommEnable := false; end end; end; RemainCount := Datacount - j - 1; // Wenn nichts abzuholen ist if RemainCount < 0 then RemainCount := 0; // Ack senden SendStr := '1'; Logger.LogMessage('Client : ' + SendStr); FIdTCPClient.IOHandler.Write(SendStr, nil); end; // Einen Datensatz komplett gelesen if DataExport then begin SLDaten.Add(SLStr); SLStr := ''; end; if Terminated then begin Break; end; end;
Delphi-Quellcode:
Offensichtlich knallt es in der dbxmss.dll.
if SQLC_Work.Connected then begin
try SQLDS_Work.Close; // Aktuellen Wareneingang ermitteln SQLDS_Work.Close; SQLDS_Work.CommandText := 'SELECT COUNT(WareneingangsNr) from WEP02.dbo.WareneingangsNr WHERE Aktiv = 1'; SQLDS_Work.Open; if SQLDS_Work.FieldCount > 0 then begin if SQLDS_Work.Fields[0].AsInteger > 1 then begin // Fehler weil mehrere Wareneingänge aktiv if Assigned(Logger) then begin Logger.LogErrorMessage('Es sind ' + IntToStr(SQLDS_Work.RecordCount) + ' Wareneingänge aktiv. Fehler bei Timer_Chart aufgetreten'); end; Exit; end else if SQLDS_Work.Fields[0].AsInteger = 0 then begin // Fehler weil kein Wareneingang aktiv Exit; end else if SQLDS_Work.Fields[0].AsInteger = 1 then begin SQLDS_Work.Close; SQLDS_Work.CommandText := 'SELECT [IdentNr], [WareneingangsNr] from WEP02.dbo.WareneingangsNr WHERE Aktiv = 1'; SQLDS_Work.Open; if SQLDS_Work.FieldCount > 1 then begin IdentNr := SQLDS_Work.Fields[0].AsString; WENr := SQLDS_Work.Fields[1].AsString; end; end; end; IdentNrOrig := IdentNr; IdentNr := StringReplace(IdentNr, '-', '', [rfReplaceAll]); SQLDS_Work.Close; SQLDS_Work.CommandText := 'Select COUNT(Gesamtergebnis) from WEP02.dbo.Teil_' + IdentNr + ' WHERE Gesamtergebnis = 1'; SQLDS_Work.Open; if SQLDS_Work.FieldCount > 0 then begin Gut := SQLDS_Work.Fields[0].AsInteger; end; SQLDS_Work.Close; SQLDS_Work.CommandText := 'Select COUNT(Gesamtergebnis) from WEP02.dbo.Teil_' + IdentNr + ' WHERE Gesamtergebnis = 0'; SQLDS_Work.Open; if SQLDS_Work.FieldCount > 0 then begin Schlecht := SQLDS_Work.Fields[0].AsInteger; end; La_Wenummer.Caption.Text := WENr; La_Teilenummer.Caption.Text := IdentNr; SQLDS_Work.Close; SQLDS_Work.CommandText := 'Select (Teilename) from WEP02.dbo.Teile WHERE IdentNr = ' + quotedStr(IdentNrOrig); SQLDS_Work.Open; if SQLDS_Work.FieldCount > 0 then begin Teilename := SQLDS_Work.Fields[0].AsString; Delete(Teilename, 1, 4); if not TryStrToInt(Teilename, SelectedModell) then begin SelectedModell := 0; end; end; Allerdings wundert mich das, da ich gelesen habe das es bei multithreading keine Probleme gibt, wenn jeder Thread seine eigene Connection hat. Die Exceptions treten meistens auf wenn auf Fields[] zugegriffen wird Danke |
AW: TSQLDataSet, TSQLConnection Multithread Exception
Mehrere Vorschläge:
Fehler abfangen:
Delphi-Quellcode:
Analog bei allen SQLDS_Work.Open einbauen.
SQLDS_Work.Close;
SQLDS_Work.CommandText := 'Select (Teilename) from WEP02.dbo.Teile WHERE IdentNr = ' + quotedStr(IdentNrOrig); Try SQLDS_Work.Open; if SQLDS_Work.FieldCount > 0 then begin Teilename := SQLDS_Work.Fields[0].AsString; Delete(Teilename, 1, 4); if not TryStrToInt(Teilename, SelectedModell) then begin SelectedModell := 0; end; end; except on e : Exception do begin if Assigned(Logger) then begin Logger.LogErrorMessage(SQLDS_Work.CommandText); Logger.LogErrorMessage(e.Message); end; end; end;
Delphi-Quellcode:
ist gut und schön, aber was ist, wenn die Ergebnismenge (warum auch immer) leer ist?
SQLDS_Work.Open;
if SQLDS_Work.FieldCount > 0 then begin
Delphi-Quellcode:
Diese Fehlerbeschreibung hilft nicht wirklich
try
SQLDS_Work.Open; if SQLDS_Work.Active then begin if not SQLDS_Work.Eof then begin if SQLDS_Work.FieldCount > 0 then begin ... end; end else begin if Assigned(Logger) then begin Logger.LogErrorMessage(SQLDS_Work.CommandText); Logger.LogErrorMessage('sinnvoller Text zur Fehlerbeschreibung (leere Ergebnismenge)...'); end; end; end else begin if Assigned(Logger) then begin Logger.LogErrorMessage(SQLDS_Work.CommandText); Logger.LogErrorMessage('sinnvoller Text zur Fehlerbeschreibung (geschlossene Datenmenge) ...'); end; end; except on e : Exception do begin if Assigned(Logger) then begin Logger.LogErrorMessage(SQLDS_Work.CommandText); Logger.LogErrorMessage(e.Message); end; end; end; Zitat:
Und wenn sie nicht bei Fields[] auftreten, wo denn dann bitte sonst noch? Ist die Ergebnismenge der Abfrage leer, dürfte ein Zugriff auf Fields[] kaum funktionieren, da es ja keinen Datensatz in der Ergebnismenge gibt und damit FieldCount = 0 ist. Was ich momentan aber nicht weiß und beurteilen kann ist, ob ein Zugriff auf FieldsCount bei einer leeren Ergebnismenge möglich ist oder hier bereits ein Fehler auftreten kann. 1. Abfrage öffnen. 2. prüfen, ob Abfrage geöffent werden konnte. 3. wenn nein, Meldung ausgeben und abbrechen. 4. prüfen, ob Ergebnismenge leer ist. 5. wenn ja, Meldung ausgeben und abbrechen. 6. prüfen, ob Anzahl der erwarteten Felder in der Ergebnismenge vorhanden ist. 7. wenn nein, Meldung ausgeben und abbrechen. 8. Werte auslesen und verarbeiten. Um alles herum per Try Except unerwartete Fehler abfangen und im Fehlerfalle Meldung ausgeben und abbrechen. Abbrechen heißt hier: Entweder das Programm beenden oder in einem sicheren und konsistenten Zustand weiterarbeiten. |
AW: TSQLDataSet, TSQLConnection Multithread Exception
Warum sollte FieldCount nichts zurückliefern? Selbst bei
Code:
werden alle Felder der Relation zurückgegeben. Und
SELECT * FROM relation WHERE 1=0
Code:
gibt immer auch einen Wert zurück. Selbst wenn kein Datensatz die Bedingung erfüllt oder relation leer ist, wird 0 zurückgeliefert.
SELECT COUNT(irgendwas) FROM relation
|
AW: TSQLDataSet, TSQLConnection Multithread Exception
Wenn dem so ist, können wir diese Fehlerursache ja ausschließen.
Klar, bei 'nem Count bekommt man mindestens 0 zurück, wenn es was nicht gibt. Was ist bei
Delphi-Quellcode:
?
SQLDS_Work.CommandText := 'SELECT [IdentNr], [WareneingangsNr] from WEP02.dbo.WareneingangsNr WHERE Aktiv = 1';
Wenn's das nicht gibt, ist die Ergebnismenge leer, EoF müsste dann erfüllt sein und FieldCount = 2. Fields[0].AsString geht dann und gibt 'ne leere Zeichenfolge zurück. Gut, können wir den Fehler auch ausschließen. |
AW: TSQLDataSet, TSQLConnection Multithread Exception
Ich frage mich was die beiden Code-Auszüge miteinander zu tun haben. Im ersten wird irgendetwas mit einer TCP-Verbindung gemacht, im zweiten werden Daten aus einer DB per SQL abgeholt. Wenn es da irgendwelche Seiteneffekte gibt, tippe ich auf Pointer-Arithmetik von Zauberlehrlingen.
Gruß K-H P.S. was ist mit durchsteppen mittels F7/F8 kann da der Fehler eingegrenzt werden? |
AW: TSQLDataSet, TSQLConnection Multithread Exception
@p80286
naja, im "Thread" gibt es sowas wie DataNotInDB und DataExport. Es könnte sich hier unter Umständen, eventuell, vielleicht um Funktionen handeln, die auf uminöse Weise auf die Datenbank zugreifen. Hier ließen sich dann Probleme und Konflikte beim Zugriff auf die Datenbank nicht zwingend ausschließen. Im Eingangspost heißt es ja u. a. Zitat:
Momentan gibt es noch zuviele :glaskugel:, aus denen gelesen werden muss, um sich dem gestellten Problem anzunähern. |
AW: TSQLDataSet, TSQLConnection Multithread Exception
Bei soviel Konjunktiv kann ich Dir nicht widersprechen. es kann natürlich sein, daß zwei Threads sich ins Gehege kommen, das sollte aber nur der Fall sein wenn sie sich eine Ressource teilen müssen, aber welche mag das wohl sein.....:glaskugel:
Gruß K-H |
AW: TSQLDataSet, TSQLConnection Multithread Exception
Hallo
danke für die vielen Antworten. @p80286 also die zwei Codeschnipsel stellen die Datenbankzugriffe da, die in der Anwendung gemacht werden. Programmübersicht: Also in Einem Thread wird eine TCPIP Kommunikation aufgebaut. Hier werden Daten abgeholt und dann mittels SQLStatements in die Datenbank geschrieben. Im VCL-Thread wird in der Datenbank nachgeschaut (select count...) wie viele Datensätze denn schon eingetragen wurden und dies wird dann visualisiert. In dem TCPIP Thread passiert eigentlich nicht recht viel mehr. Hier wir weiter oben lediglich Kommunikationsgeschichten abgearbeitet. Daher dann die Frage Datacount > 0 und dann gehts los mit Datenbank eintragen. Die Eigenschaften des Threads wie z.B.: DataNotinDB oder weitere sind mittels CriticalSections geschützt und haben ihre Get und Set Methoden mit denen darauf zugegriffen wird Ich habe selbstverständlich schon mit F7/F8 versucht zu debuggen. Allerdings lässt sich der Fehler nicht genau lokalisieren. Also ich arbiete mit XE5 Enterprise und witzigerweise schmiert der Debugger auch ab wenn diese $C000005 Exception auftritt. Ich kann am Montag gerne einen Auszug davon einstellen. Zitat:
Aber vorab schon mal so viel. In der Funktion ProduktAuswerten wird das gemacht. Hier werden die SQLStatments generiert und abgesetzt. Jetzt noch eine ganz grundsätzliche Frage. Es ist rein theoretisch schon möglich von zwei Threads aus auf die selbe Datenbank zuzugreifen? Da hier ja der fehler in der dbxmss.dll auftritt. Vielen Dank einen schönen Abend |
AW: TSQLDataSet, TSQLConnection Multithread Exception
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo.
Im Anhang ist jetzt das .pas file in dem der Thread gestartet wird und die Kommunikation läuft. Den anderen Datenbankzugriff im Main findet ihr ja auf der ersten Seite. Ich hoffe das jetzt nicht mehr fehlt. Ich werde jetzt trotzdem gleich mal den Vorschlag von nahpets umsetzen und sehen ob ich zu einem Ergebnis komme. Wenn ihr Vorschläge hab, nur her damit |
AW: TSQLDataSet, TSQLConnection Multithread Exception
Hallo,
nach längerem vergeblichem probieren bin ich jetzt auf FireDAC umgestiegen. Einach alle Komponenten ausgetauscht. Und es funktioniert |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:14 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