Ich arbeite derzeit an einer DLL, die mehrere parallele ODBC-Verbindungen zu Microsoft SQL-Servern verwalten soll. Ich bediene mich da der TODBCConnection, sowie TSQLQuery und TSQLTransaction. Das funktioniert auch soweit. Allerdings steht mir ein ganz spezifisches Problem im Weg.
In meinem Testprogramm (in Delphi 5 geschrieben) lasse ich einen Timer laufen, der eine vorher geöffnete Verbindung benutzt, um eine SELECT-Abfrage auszuführen, die Daten in ein stinknormales Grid (hier: XStringGrid) schreibt und danach per Insert einen Datensatz mit Zufallsdaten dranhängt. Die Verbindung bleibt danach geöffnet, bis das Testprogramm beendet wird. Soweit klappt das auch. Das Problem tritt beim Beenden des Programms auf. Nachdem ich den Timer gestoppt habe, erhalte ich beim Trennen der Verbindung eine Exception der Klasse EAccessViolation:
"Zugriffsverletzung bei Adresse 10006D41 in Modul 'msdb.dll'. Schreiben von Adresse 00000000'. Prozess wurde angehalten. Mit einzelne Anweisung oder Start fortsetzen."
Ich habe das Problem soweit einkreisen können, dass es nur dann auftritt, wenn ich mit dieser Datenbankverbindung erst eine SELECT-Abfrage ausführe und dann einen INSERT, UPDATE oder DELETE, und soweit ich das sagen kann, tritt der Fehler schon beim Aufruf der Trennfunktion für die Verbindung auf. Wird zuletzt ein SELECT durchgeführt, beendet das Programm ohne Fehlermeldung. Dieser Fehler tritt schon auf, wenn ich meine DLL-Funktion zum Schließen der Verbindung aufrufe.
Ich habe parallel noch einen zweiten Timer laufen, der zwei Verbindungen behandelt: Eine Verbindung holt Daten aus einer Datenbank, und die zweite Verbindung schreibt sie per INSERT in eine andere Datenbank. Auch das funktioniert tadellos.
Ich vermute ein Problem im Zusammenspiel mit der TSQLQuery-Instanz. Es sieht schematisch so aus:
Datenbankverbindung öffnen:
Code: Alles auswählen
db := TODBCConnection.Create(nil);
sqlquery := TSQLQuery.Create(nil);
sqltransaction := TSQLTransaction.Create(nil);
sqlquery.DataBase := db;
db.Transaction := sqltransaction;
sqlquery.Transaction := sqltransaction;
db.HostName := DBHost;
db.DatabaseName := DBName;
db.UserName := Username;
db.Password := Password;
db.Open;
Code: Alles auswählen
if (copy(query,1,6)="SELECT") then
begin
sqlquery.Active := false;
sqlquery.SQL.Text := query;
sqlquery.UsePrimaryKeyAsKey := false;
sqlquery.Open;
rcount := 0;
while not sqlquery.EOF do
begin
inc(rcount);
sqlquery.Next;
end;
sqlquery.First;
queryDB := rcount;
end
else if (copy(query,1,6)="INSERT") then
begin
sqlquery.ClearFields;
sqlquery.Active := false;
sqlquery.SQL.Text := query;
sqlquery.UsePrimaryKeyAsKey := true;
sqlquery.ExecSQL;
queryDB := 0;
end;
Code: Alles auswählen
sqlquery.Active := false;
db.Close;
if NOT db.Connected then
begin
sqlquery.free;
sqltransaction.free;
db.free;
CloseDB := true;
end;
Zusatzinformationen:
- Lazarus 0.9.28.2 mit FPC 2.2.4
- Win XP Pro SP3
- Lokaler MS SQL Server 2005 EE