2010-04-13 14 views
8

Sto giocando con la gestione degli errori e ho un piccolo problema. Mi collego con un database usando il modulo DBI.Perl: errore di cattura senza morire

Faccio la mia gestione degli errori utilizzando una subroutine che richiamo un errore.

posso prendere i miei stampi e gestirli bene, ma quando la mia connessione al database non riesce, il modulo DBI apparentemente stampa fuori di essa la propria filiera:

DBI connect(...) failed: ORA-12154: TNS:could not resolve the connect identifier specified (DBD ERROR: OCIServerAttach) at ...

Come potrei fare per la cattura di questo?

Ho provato ad utilizzare $SIG{__DIE__} in questo modo:

local $SIG{__DIE__} = sub { 
    my $e = shift; 
    print "Error: " .$e; 
}; 

Questa è sul fondo del mio file principale, in questo file anche io chiamo la subroutine di connessione che è disponibile in un modulo della mia. Ho anche provato a mettere questo pezzo di codice sul fondo del mio modulo, ma le stampe ancora l'errore senza il

Error:

di fronte ad essa.

risposta

3

Va bene, trovato la soluzione, a quanto pare avevo bisogno __WARN__ invece di __DIE__ e questo pezzo di codice necessario per essere nella parte superiore del file, prima dove è stato gettato l'errore, a differenza l'esempio che ho letto affermato :)

+3

Questo è corretto, si trattava di un avviso e non di una morte e il gestore deve essere installato per primo. Puoi installarlo in qualsiasi modulo se lo sposti in un 'BEGIN {} '. – Ether

+0

leggi anche questo, grazie per la verifica. – Pmarcoen

2

Ci sono molti switch in DBI, come PrintError, RaiseError, ecc. Che è possibile regolare. Vedi http://search.cpan.org/perldoc?DBI

+0

hmm non c'è una soluzione più generica? In modo che io possa catturare tutti gli altri errori con 1 funzione. Potrei usare molti moduli che hanno molti modi per generare errori, voglio essere indipendente da questo .. – Pmarcoen

+0

DBI ha anche un metodo HandleError. O se si imposta PrintError su false, RaiseError su true, si dovrebbe chiamare la gestione degli errori di (Pmarcoen). – runrig

0

Questo non è così generico come un raccoglitore di fustelle complessivo, ma in particolare per la gestione degli errori DBI abbiamo in realtà un nostro modulo che fornisce i wrapper attorno alle chiamate al database; e una delle funzionalità del modulo è di avvolgere eval (in base a un flag) attorno a ciascuna chiamata DBI.

Questo ci consente di eseguire la gestione personalizzata degli errori sul livello di accesso ai dati, ad esempio tentativi di query, statistiche, failover automatico e altro - tutto trasparente per il resto del codice.

8

DBI connect(...) failed: ORA-12154: TNS:could not resolve the connect identifier specified (DBD ERROR: OCIServerAttach) at ...

How would I go about catching this ?

Per catturare e gestire questo livello di errore, utilizzare eval in forma di blocco, "eval {...}". Questo catturerà qualsiasi dado che accade nel sottocodice. Se il codice all'interno di un blocco eval muore, verrà impostato $ @ e il blocco restituirà false. Se il codice non muore, $ @ verrà impostato su "".

L'utilizzo della gestione dei segnali tramite SIG {WARN} e SIG {DIE} è problematico dal momento che sono globali, ci sono anche condizioni di gara da considerare (cosa succede se ottengo un segnale mentre gestisco un segnale diverso? Ecc. I problemi tradizionali del calcolo basato sul segnale). Probabilmente stai scrivendo un codice a thread singolo, quindi non sei preoccupato dei problemi di concorrenza di più cose che chiamano morire, ma c'è un utente da considerare (forse invierà un SIGKILL mentre stai provando ad aprire la connessione DBI)

In questo caso specifico, si utilizza DBI. Con DBI, puoi controllare cosa succede in caso di errore, se deve morire, avvertire o fallire silenziosamente e attendere che tu controlli lo stato di ritorno.

Ecco un esempio di base dell'utilizzo di eval {...}.

my $dbh = eval { DBI->connect(@args) }; 
if ([email protected]) 
{ 
    #DBI->connect threw an error via die 
    if ([email protected] =~ m/ORA-12154/i) 
    { 
     #handle this error, so I can clean up and continue 
    } 
    elsif ([email protected] =~ m/SOME \s* other \s* ERROR \s+ string/ix) 
    { 
     #I can't handle this error, but I can translate it 
     die "our internal error code #7"; 
    } 
    else 
    { 
     die [email protected]; #re-throw the die 
    } 
} 

Ci sono alcuni problemi minori con l'utilizzo di eval in questo modo, che ha a che fare con lo scopo globale di $ @. La pagina cpan Try::Tiny ha un'ottima spiegazione. Prova :: Tiny gestisce una configurazione di blocco Try/catch minima e gestisce la localizzazione di $ @ e la gestione degli altri casi limite.

+0

Questo è stato il modo in cui l'ho avuto all'inizio, tuttavia tuttavia non rileva gli avvertimenti che volevo segnalare. Perciò devo usare SIG {WARN}. – Pmarcoen

2

includere questo nella vostra SIG{__DIE__} blocco:

### Check if exceptions being caught. 
return if $^S; 

Questo eviterà che il tuo gestore di essere utilizzato su codice di eccezione-based che genera un dado all'interno di un blocco eval.

Problemi correlati