2010-02-18 11 views
11

Devo rilevare quando un componente TAdoConnection ha perso la connessione con il server. Ho provato a utilizzare l'evento OnDisconnect ma questo si attiva solo quando viene chiamato il metodo Close o la proprietà Connected è impostata su false.Come posso rilevare che un TadoConnection ha perso la comunicazione con il server?

Un'altra opzione Ho provato utilizza un TTimer e l'esecuzione di una query come questa

SELECT 1 RESULT FROM DUAL 

in caso OnTimer, la cattura qualsiasi eccezione che si verifica.

C'è una soluzione migliore per rilevare che la connessione è stata persa?

+2

SQL Server consente a Qry.ExecSQL con SQL.Text = '' come query (ma non ''). Questo può essere eseguito centinaia di volte al secondo. –

risposta

11

Vedo la tabella DUAL. Significa che stai usando l'Oracle :)

Per la maggior parte (tutti?) Dei DBMS client/server non c'è modo di rilevare, che una connessione è persa, se non quella di chiedere un DBMS per qualche azione. E ci sono molte ragioni, perché una connessione è persa. Potrebbe essere un errore di rete, potrebbe essere ..., potrebbe essere un DBA che ha arrestato un DB.

Molte API DBMS, incluso Oracle OCI, dispongono delle funzioni speciali che consentono di eseguire il ping di un DBMS. Il "ping" è una richiesta il più piccola possibile a un DBMS. Il precedente SELECT richiede molto più lavoro, rispetto a tale ping.

Ma non tutti i componenti di accesso ai dati, incluso ADO, consentono di eseguire il ping di un DBMS utilizzando la chiamata ping dell'API DBMS. Quindi devi usare un comando SQL. Quindi, la SELECT sopra è corretta con ADO. Altra opzione - BEGIN NULL; FINE;. Potrebbe utilizzare meno risorse DBMS (nessuna necessità di ottimizzazione, nessuna descrizione di un set di risultati, ecc.).

TTimer è OK. La query deve essere eseguita in un thread, in cui viene utilizzata la connessione corrispondente. Non è un must, anche se, ma è un problema diverso.

Il potenziale problema potrebbe essere quello di chiudere una connessione, quando una connessione viene persa. Poiché la chiusura della connessione può generare un'eccezione a causa dell'API DBMS potrebbe essere in uno stato non riuscito.

Kind of ... che

+1

Ciao da-soft. se usiamo TADOConnection nel thread principale dovremmo "ping" lo sql dal thread principale? dovremmo anche utilizzare la stessa connessione TADOC o utilizzare un "TADOConnection" ping diverso? – zig

3

@Dimitry risposta è molto buona. Se è fondamentale per la tua applicazione sapere se il connectino è perso, l'approccio TTimer (con una minima necessità).

Se si desidera sapere quando un'istruzione fallisce a causa di una "comunicazione persa", è possibile utilizzare l'evento Application.OnException e ispezionare le proprietà Exception.

Ho creato il seguente codice come esempio, utilizzando il componente ApplicationEvents. È solo una bozza con l'idea, non adatta alla produzione.

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; 

Cordiali saluti.

-1

Questo è uno dei motivi per eliminare ADO e utilizzare DBX. L'architettura di Ado è basata sul cursore del server e questo non richiede di perdere la connessione al server in qualsiasi momento. Se la connessione viene persa in alcune circostanze, la connessione non sarà in grado di rialzarsi. D'altra parte DBX è in grado di riconnettersi vicino a sempre a causa della sua architettura scollegata.

+0

Questo non è vero. ADO può essere utilizzato come server come cursori client e consente di applicare un modello di set di dati disconnessi. Da about.com: Per creare un recordset ADO disconnesso, è necessario innanzitutto impostare la proprietà CursorLocation ADODataSets su "clUseClient". Quindi aprire l'oggetto Recordset. Quindi imposta la connessione ADODatasets su Nil. Non chiudere il blocco ADOD. –

+0

Sì ADO può funzionare in modalità valigetta. Ma la risposta di DBX a questo problema è più naturale e prevedibile. –

0

Ho lo stesso problema sul pool di connessione. Ho sviluppato una classe TADOSQLConnectionPool per aiutare a riutilizzare la connessione per i lavori DB dei thread.Quando voglio assegnare una connessione a un thread, ho provato a verificarne l'integrità eseguendo il lavoro minimo come "Seleziona 1". In questo modo, sarò sicuro della connessione. Se fallisce, disporrò di tutte le connessioni per ricrearle alla prossima richiesta.