2010-02-18 2 views
11

Ich muss erkennen, wenn eine TAdoConnection Komponente die Verbindung mit dem Server verloren hat. Ich habe versucht, das Ereignis OnDisconnect zu verwenden, aber das wird nur ausgelöst, wenn die Close-Methode aufgerufen oder die Connected-Eigenschaft auf false festgelegt wird.Wie kann ich erkennen, dass ein TadoConnection die Kommunikation mit dem Server verloren hat?

Eine weitere Option, die ich habe versucht, wie diese

SELECT 1 RESULT FROM DUAL 

im OnTimer Ereignis eine TTimer und Ausführen einer Abfrage verwendet, jede Ausnahme zu kontrollieren, die auftritt.

Gibt es eine bessere Option, um zu erkennen, dass die Verbindung verloren gegangen ist?

+2

SQL Server ermöglicht Qry.ExecSQL mit SQL.Text = '' als eine Abfrage (aber nicht ''). Dies kann Hunderte von Malen pro Sekunde ausgeführt werden. –

Antwort

11

Ich sehe die DUAL-Tabelle. Mittel, können Sie die Oracle verwenden :)

Für die meisten (alle?) Client/Server-DBMS gibt es keine Möglichkeit zu erkennen, dass eine Verbindung Losted ist, anders als ein DBMS für eine Aktion zu fragen. Und es gibt viele Gründe, warum eine Verbindung losted ist. Kann ein Netzwerkfehler sein, möglicherweise ..., kann ein DBA eine DB shutdowned sein.

Viele DBMS-APIs, einschließlich Oracle OCI, haben spezielle Funktionen, die es ermöglichen, ein DBMS zu pingen. Der "Ping" ist eine möglichst kleine Anfrage an ein DBMS. Das obige SELECT erfordert viel mehr Arbeit als ein solches Ping.

Nicht alle Datenzugriffskomponenten, einschließlich ADO, ermöglichen das Pingen eines DBMS mithilfe des DBMS-API-Pingaufrufs. Dann müssen Sie einen SQL-Befehl verwenden. Also, das obige SELECT ist korrekt mit ADO. Andere Option - BEGIN NULL; ENDE;. Möglicherweise verwendet es weniger DBMS-Ressourcen (kein Optimierer, keine Beschreibung einer Ergebnismenge usw.).

TTimer ist OK. Die Abfrage sollte in einem Thread ausgeführt werden, in dem die entsprechende Verbindung verwendet wird. Kein Muss, aber es ist ein anderes Thema.

Möglicherweise besteht das Problem darin, eine Verbindung zu schließen, wenn eine Verbindung unterbrochen wird. Da ein Verbindungsabschluss eine Ausnahme wegen der DBMS-API auslösen kann, befindet sich der Fehler möglicherweise in einem Fehlerzustand.

Art, dass ...

+1

Hallo da-weich. Wenn wir TADOConnection im Hauptthread verwenden, sollten wir die SQL aus dem Hauptthread "ping"? sollten wir auch die gleiche TADOConnection verwenden oder eine andere "ping" TADOConnection verwenden? – zig

3

@Dimitry Antwort ist sehr gut. Wenn es für Ihre Anwendung wichtig ist zu wissen, ob der Connectino verloren ist, ist der TTimer-Ansatz (mit einer minimalen Operation).

Wenn Sie nur wissen möchten, wenn eine Anweisung aufgrund einer "verlorenen Kommunikation" fehlschlägt, können Sie das Application.OnException-Ereignis verwenden und die Exception-Eigenschaften überprüfen.

Ich habe den folgenden Code als Beispiel mit der ApplicationEvents-Komponente gemacht. Ist nur ein Entwurf mit der Idee, nicht für die Produktion geeignet.

uses 
    ComObj; 

procedure TForm2.ApplicationEvents1Exception(Sender: TObject; E: Exception); 
var 
    EO: EOleException; 
begin 
    if E is EOLEException then 
    begin 
    EO := EOleException(E); 
    //connection error (disconnected) 
    if EO.ErrorCode = E_FAIL then 
    begin 
     try 
     try 
      ADOConnection1.Close; 
     except 
      ; 
     end; 
     ADOConnection1.Open; 
     ShowMessage('Database connection failed and re-established, please retry!'); 
     except 
     on E:Exception do 
      ShowMessageFmt('Database connection failed permanently. ' 
      + 'Please, retry later'#13'Error message: %s', [E.Message]); 
     end; 
    end 
    else 
     ShowMessage(E.Message + ' ' + IntToStr(EO.ErrorCode)); 
    end 
    else 
    ShowMessage(E.ClassName + #13 + E.Message); 
end; 

Mit freundlichen Grüßen.

-1

Dies ist einer der Gründe, ADO zu löschen und DBX zu verwenden. Die Ado-Architektur basiert auf dem Server-Cursor und diese Anforderung besteht nicht darin, die Verbindung zum Server jederzeit zu verlieren. Wenn die Verbindung unter bestimmten Umständen unterbrochen wird, kann die Verbindung nicht wieder hergestellt werden. Auf der anderen Seite ist DBX in der Lage, aufgrund seiner getrennten Architektur in der Nähe von immer wieder zu verbinden.

+0

Dies ist nicht wahr. ADO kann Server als Clientcursor verwenden und ein getrenntes Datasetmodell anwenden. About.com: Um ein getrenntes ADO-Recordset zu erstellen, müssen Sie zuerst die ADODataSets CursorLocation-Eigenschaft auf "ClUseClient" festlegen. Öffnen Sie dann das Recordset. Setzen Sie dann die Verbindung ADODatasets zu Nil. Schließen Sie das ADODaset nicht. –

+0

Ja ADO kann im Aktenkoffermodus arbeiten. Aber die Antwort von DBX auf dieses Problem ist natürlicher und vorhersagbarer. –

0

Ich habe dasselbe Problem auf Verbindungspool. Ich habe eine TADOSQLConnectionPool-Klasse entwickelt, um die Wiederverwendung der Verbindung für die Thread-DB zu unterstützen.Wenn ich eine Verbindung zu einem Thread zuweisen möchte, habe ich versucht, den Zustand zu überprüfen, indem ich einen minimalen Job als "Select 1" ausgeführt habe. Auf diese Weise werde ich sicher sein, über connection.If es ausfällt, werde ich alle Verbindungen verfügen bei der nächsten Anfrage zu erstellen.

Verwandte Themen