Implementare la gestione degli errori T-SQL
Un errore indica un problema o un problema rilevante che si verifica durante un'operazione di database. Gli errori possono essere generati dal motore di database di SQL Server in risposta a un evento o a un errore a livello di sistema; oppure è possibile generare errori dell'applicazione nel codice Transact-SQL.
Elementi degli errori del motore di database
Indipendentemente dalla causa, ogni errore è costituito dagli elementi seguenti:
- Numero errore - Numero univoco che identifica l'errore specifico.
- Messaggio di errore : testo che descrive l'errore.
- Gravità: numero compreso tra 1 e 25 indicante l'importanza.
- Stato : codice di stato interno per la condizione del motore di database.
- Procedura - Il nome della stored procedure o del trigger in cui si è verificato l'errore.
- Numero di riga : l'istruzione nel batch o nella routine ha generato l'errore.
Errori di sistema
Gli errori di sistema sono predefiniti ed è possibile visualizzarli nella vista di sistema sys.messages . Quando si verifica un errore di sistema, SQL Server può eseguire un'azione correttiva automatica, a seconda della gravità dell'errore. Ad esempio, quando si verifica un errore di gravità elevata, SQL Server può portare un database offline o persino arrestare il servizio motore di database.
Errori personalizzati
È possibile generare errori nel codice Transact-SQL per rispondere a condizioni specifiche dell'applicazione o per personalizzare le informazioni inviate alle applicazioni client in risposta agli errori di sistema. Questi errori dell'applicazione possono essere definiti inline in cui vengono generati oppure è possibile definirli nella tabella sys.messages insieme agli errori forniti dal sistema. I numeri di errore usati per gli errori personalizzati devono essere 50001 o versioni successive.
Per aggiungere un messaggio di errore personalizzato a sys.messages, usare sp_addmessage. L'utente per il messaggio deve essere un membro di uno dei ruoli predefiniti del server: sysadmin o serveradmin.
Questa è la sintassi sp_addmessage:
sp_addmessage [ @msgnum= ] msg_id , [ @severity= ] severity , [ @msgtext= ] 'msg'
[ , [ @lang= ] 'language' ]
[ , [ @with_log= ] { 'TRUE' | 'FALSE' } ]
[ , [ @replace= ] 'replace' ]
Di seguito è riportato un esempio di messaggio di errore personalizzato che usa questa sintassi:
sp_addmessage 50001, 10, N’Unexpected value entered’;
Annotazioni
sp_addmessageè supportato solo in SQL Server. In database SQL di Azure e Istanza gestita di SQL di Azure sp_addmessage non è supportato, quindi non è possibile fare riferimento a un msg_id valore maggiore di 50000. In queste piattaforme, usare inline RAISERROR con una stringa di messaggio o THROW in combinazione con FORMATMESSAGE(), invece.
Inoltre, è possibile definire messaggi di errore personalizzati, i membri del ruolo del server sysadmin possono anche usare un parametro aggiuntivo , @with_log. Se impostato su TRUE, l'errore verrà registrato anche nel registro applicazioni di Windows. Qualsiasi messaggio scritto nel registro applicazioni di Windows viene scritto anche nel log degli errori di SQL Server. Si dovrebbe essere prudenti con l'uso dell'opzione @with_log perché gli amministratori di rete e di sistema tendono a non gradire le applicazioni che sono "verbose" nei log di sistema. Tuttavia, se l'errore deve essere intrappolato da un avviso, è necessario prima scrivere l'errore nel registro applicazioni di Windows.
Annotazioni
La generazione di errori di sistema non è supportata.
I messaggi possono essere sostituiti senza eliminarli prima usando l'opzione @replace = 'replace'.
I messaggi sono personalizzabili e possono essere aggiunti diversi per lo stesso numero di errore per più lingue, in base a un valore language_id.
Annotazioni
I messaggi in inglese sono language_id 1033.
Generare errori usando RAISERROR
Annotazioni
RAISERROR è deprecato per il nuovo sviluppo. Usare THROW per il nuovo codice T-SQL.
RAISERROR rimane utile per il codice legacy, per aumentare i livelli di gravità superiori a 16 (che THROW non possono eseguire direttamente) e per printfla formattazione dinamica dei messaggi in stile (l'alternativa moderna è FORMATMESSAGE() combinata con THROW).
Sia PRINT che RAISERROR possono essere usati per restituire informazioni o messaggi di avviso alle applicazioni.
RAISERROR consente alle applicazioni di generare un errore che potrebbe quindi essere intercettato dal processo chiamante.
RAISERROR
La possibilità di generare errori in T-SQL semplifica la gestione degli errori nell'applicazione, perché viene inviata come qualsiasi altro errore di sistema.
RAISERROR viene usato per:
- Risolvere i problemi relativi al codice T-SQL.
- Controllare i valori dei dati.
- Restituisce messaggi contenenti testo variabile.
Annotazioni
L'uso di un'istruzione PRINT è simile alla generazione di un errore di gravità 10.
Di seguito è riportato un esempio di messaggio di errore personalizzato che usa RAISERROR.
RAISERROR (N'%s %d', -- Message text,
10, -- Severity,
1, -- State,
N'Custom error message number',
2)
Quando viene attivato, restituisce:
Custom error message number 2
Nell'esempio precedente %d è un segnaposto per un numero e %s è un segnaposto per una stringa. Inoltre, è consigliabile notare che un numero di messaggio non è stato menzionato. Quando vengono generati errori con stringhe di messaggio usando questa sintassi, hanno sempre il numero di errore 50000.
Generare errori usando THROW
L'istruzione THROW offre un metodo più semplice per generare errori nel codice ed è l'approccio consigliato per il nuovo sviluppo T-SQL. Gli errori devono avere un numero di errore di almeno 50000.
THROW
THROW differisce da RAISERROR in diversi modi:
- Quando
THROWgenera una nuova eccezione, la gravità è sempre 16. QuandoTHROWviene usato per rigenerare un'eccezione esistente (senzaTHROWparametri all'interno di unCATCHblocco), viene mantenuta la gravità dell'eccezione originale. Questo è il motivo per cuiTHROWè preferibile generare nuovamente errori di sistema da unCATCHblocco. - I messaggi restituiti da
THROWnon sono correlati ad alcuna voce insys.messages. -
THROWSET XACT_ABORTrispetta . QuandoSET XACT_ABORT ONè attivo, viene eseguito automaticamente il rollback della transazione corrente da un'eccezione generataTHROW.RAISERRORnon rispettaSET XACT_ABORT: questo è uno dei motiviTHROWprincipali è preferibile per il nuovo sviluppo.
Importante
L'istruzione immediatamente prima THROW di deve terminare con un punto e virgola (;), in caso contrario viene visualizzato un errore di sintassi. Si tratta di un blocco a cascata comune quando si THROW adotta un codice esistente che omette punti e virgola.
; THROW 50001, 'An error occurred', 1;
Catturare i codici di errore usando @@Error
La maggior parte del codice di gestione degli errori tradizionale nelle applicazioni SQL Server è stata creata usando @@ERROR. La gestione strutturata delle eccezioni offre un'alternativa più potente all'uso @@ERROR ed è l'approccio consigliato per il nuovo codice T-SQL. Verrà illustrato nella lezione successiva. Una grande quantità di codice di gestione degli errori SQL Server esistente si basa su @@ERROR, quindi è importante comprendere come usarlo.
Errore: @@ERROR
@@ERROR è una variabile di sistema che contiene il numero di errore dell'ultimo errore che si è verificato. Una sfida significativa con @@ERROR è che il valore che contiene viene reimpostato rapidamente man mano che viene eseguita ogni istruzione aggiuntiva.
Si consideri ad esempio il codice seguente:
RAISERROR(N'Message', 16, 1);
IF @@ERROR <> 0
PRINT 'Error=' + CAST(@@ERROR AS VARCHAR(8));
GO
Ci si potrebbe aspettare che, quando il codice viene eseguito, restituisce il numero di errore in una stringa stampata. Tuttavia, quando viene eseguito il codice, restituisce:
Msg 50000, Level 16, State 1, Line 1
Message
Error=0
L'errore è stato generato ma il messaggio stampato è "Error=0". Nella prima riga dell'output è possibile notare che l'errore, come previsto, è stato effettivamente 50000, con un messaggio passato a RAISERROR. Ciò è dovuto al fatto che l'istruzione IF che segue l'istruzione RAISERROR è stata eseguita correttamente e ha causato la reimpostazione del @@ERROR valore.
Per questo motivo, quando si lavora con @@ERROR, è importante acquisire il numero di errore in una variabile non appena viene generato e quindi continuare l'elaborazione con la variabile.
Esaminare il codice seguente che illustra quanto segue:
DECLARE @ErrorValue int;
RAISERROR(N'Message', 16, 1);
SET @ErrorValue = @@ERROR;
IF @ErrorValue <> 0
PRINT 'Error=' + CAST(@ErrorValue AS VARCHAR(8));
Quando questo codice viene eseguito, restituisce l'output seguente:
Msg 50000, Level 16, State 1, Line 2
Message
Error=50000
Il numero di errore viene segnalato correttamente.
Centralizzazione della gestione degli errori
Un altro problema significativo con l'uso @@ERROR di per la gestione degli errori è che è difficile centralizzare all'interno del codice T-SQL. La gestione degli errori tende a finire sparsa in tutto il codice. Sarebbe possibile centralizzare la gestione degli errori usando @@ERROR in qualche misura, usando etichette e GOTO istruzioni. Tuttavia, questo sarebbe disapprovato dalla maggior parte degli sviluppatori al giorno d'oggi come una cattiva pratica di programmazione.
Creare avvisi di errore
Per determinate categorie di errori, gli amministratori potrebbero creare avvisi di SQL Server, perché desiderano ricevere una notifica non appena si verificano. Ciò può essere applicato anche ai messaggi di errore definiti dall'utente. Ad esempio, potrebbe essere necessario generare un avviso ogni volta che viene riempito un log delle transazioni. Gli avvisi vengono comunemente usati per portare errori di gravità elevata (ad esempio gravità 19 o superiore) all'attenzione degli amministratori.
Generazione di avvisi
È possibile creare avvisi per messaggi di errore specifici. Il servizio di avviso si registra come servizio di callback con il servizio di registrazione eventi. Ciò significa che gli avvisi funzionano solo sugli errori registrati.
Esistono due modi per sollevare un errore e generare un avviso: è possibile usare l'opzione WITH LOG quando si solleva l'errore o il messaggio può essere modificato per essere registrato eseguendo sp_altermessage. L'opzione WITH LOG ha effetto solo sull'istruzione corrente. L'uso di sp_altermessage modifica il comportamento di errore per tutti gli usi futuri.