hallo,
ich beziehe mich hierbei auf
diesen Thread, wobei diese fragestellung, in meinen augen, nichts mehr mit dem problem hier zu tun hat, daher ein neues Topic.
und zwar geht es darum, dass ich eine klasse habe, die datenbankabfragen tätigt. diese hat drei public-methoden, die allerdings, nur mit angepassten parametern, eine private-methode aufrufen. hier vorab schon mal der 1:1 code von der private-methode.
Delphi-Quellcode:
// private-Methode
function TDatabase._execSQL(
SQL:
String;
var ATable: TADDatSTable): Boolean;
var
cmd : Char;
b : Boolean;
sqlList : TStringList;
s :
String;
begin
Result := False;
SQL := trim(
SQL);
// Auf Verbindung prüfen
if not FConnection.Connected
then
exit;
try
// Länge des SQL-Befehls prüfen
if (length(
SQL) < 1)
then
raise Exception.Create('
Es wurde kein SQL-Befehl übergeben');
// SQL-Befehl prüfen
cmd :=
SQL[1];
if (
not (cmd
in ALLOWED_DATABASE_COMMANDS) )
then
raise Exception.Create('
Es wurde kein korrekter SQL-Befehl übergeben');
// Unerlaubte Zeichen auskommentieren (für Oracle)
maskSpecialChars(
SQL);
sqlList := TStringList.Create;
try
// SQL in Zeilen aufsplitten, in so fern #13 im SQL-String vorkommen
while pos(#13,
SQL) > 0
do
begin
s := copy(
SQL, 1, pos(#13,
SQL) - 1);
delete(
SQL, 1, pos(#13,
SQL));
sqlList.Add(trim(s));
end;
sqlList.Add(
SQL);
// letzter Part bzw alleiniger SQL-Befehl ohne mehrere Zeilen
// Kritische Sektion betreten
FCriticalSection.Enter();
// SQL ausführen
try
FCommand.CommandText := sqlList;
if (cmd = '
S')
then
begin
try
if not Assigned(ATable)
then
exit;
// SELECT-Abfrage mit Ergebnisausgabe
FCommand.Open;
// Abfrage wird an DB gesendet und Ergebnis wird in Empfang genommen
FCommand.Define(ATable);
// Tabelle bekommt hier die Spalten mitgeteilt
FCommand.Fetch(ATable, True);
// Übertrag der empfangenen Daten an die Tabelle
FCommand.Close;
Result := True;
except
raise;
end;
end
else begin
// -> Exception, wenn die Abfrage nicht geklappt hat
// ansonsten tritt kein Fehler auf
try
FCommand.Execute();
Result := True;
except
raise;
end;
end;
finally
// Kritische Sektion wieder freigeben
FCriticalSection.Release();
end;
except
on E :
Exception do
begin
// Wenn es zu einer internen Exception kommt, dann wird nur in die
// Log-Datei geloggt, da es sonst unter Umständen zu einer Endlos-
// schleife werden kann
b := FLog.LogToDatabase;
FLog.LogToDatabase := False;
Log(E.
Message, ltError);
FLog.LogToDatabase := b;
end;
end;
finally
FreeAndNil(sqlList);
end;
end;
die public-methoden, die eben die private-methode aufrufen, haben die folgenden aufgaben: einerseits das handling von select-abfragen, also mit ergebnis-tabelle, zum anderen inserts, delete etc, mit ergebnis über den erfolg und das dritte wäre die transaktion (nur inserts, delete etc.), eben auch mit dem ergebnis über erfolg der queries.
Delphi-Quellcode:
function execSQL(aSQL: String): Boolean;
var
tmp : TADDatSTable;
begin
{ ... }
Result := _execSQL(aSQL, tmp);
{ ... }
end;
function execSQL(aSQL: String; var aTable: TADDatSTable): Boolean;
begin
{ ... }
Result := _execSQL(aSQL, aTable);
{ ... }
end;
function execTransaction(aSQLList: TStringList): Boolean;
var
i : Integer;
tmp
begin
{ ... }
{ Transaktion wird gestartet}
Result := True;
for i := 0 to aSQLList.Count - 1 do
begin
if not (execSQL(aSQLList[i])) then
begin
Result := False;
break;
end;
end;
{ Transaktion wird beendet }
{ ... }
end;
zudem ist noch zu sagen, dass ich die variable FCriticalSection : TCriticalSection in der klasse TDatabase private definiert habe.
nun zum eigentlichen problem: in zeile 41 der private-methode betrete ich ja die kritische sektion und jeder andere thread, der eben ein
query ausgeführt haben möchte wartet an dieser stelle -- so habe ich das bisher halt verstanden. wenn der thread, der gerade den code ausführt, d.h. andere threads blockiert, zeile 73 erreicht so gibt er diesen abschnitt für andere threads wieder frei und der nächste thread kann diesen code ausführen. blockiert allerdings wieder die anderen threads.
die frage hierbei ist: ist das die richtige position, in so fern ich einen normalen
query ausführe, also noch keine transaktion, da dies ein gesondertes problem darsellt??? was passiert mit den variablen innerhalb der methode _execSQL, wenn zwei threads mehr oder weniger gleichzeitig in diese methode rein laufen und diesen code ausführen, eben bis zur besagten stelle? was passiert dabei im speichern? werden zwei "instanzen" (ich weiß nicht, wie man dazu sagt) von dieser methode im speicher gehalten, oder nur eine? denn dann könnte ja das problem auftreten, dass die variablen in der methode überschrieben werden, eben ein zweiter thread die daten überschreibt, die der ausführende thread gerader braucht!?
ich hoffe, ihr könnt mir hierbei etwas weiterhelfen.
vielleicht noch eine frage am rande: wie lange wartet ein thread eigentlich, wenn er nicht sofort den code ausführen kann? halt er einfach an dieser stelle an, oder wird ein neues execute aufgerufen?
hätte jemand evtl. ein sehr ausführliches tutorial über threads? wäre echt klasse. habe das von luckie schon gelesen, aber das geht mir nicht ausreichend ins detail!
mit freundlichen grüßen
der hai
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)