La gestione degli errori e l'organizzazione del logging in SQL hanno acquisito particolare popolarità con lo sviluppo di processi aziendali complessi, quando è diventato importante non solo fermare l'esecuzione in caso di errore, ma anche registrare il fatto di un guasto e, se possibile, continuare a lavorare. Inizialmente, SQL non disponeva di strumenti avanzati per il try-catch, e ogni DBMS offriva i propri meccanismi.
Storia della questione:
Le versioni iniziali degli standard SQL non avevano operatori incorporati per la cattura degli errori nelle procedure. Successivamente, i produttori hanno iniziato a implementare costrutti come TRY...CATCH in Microsoft SQL Server, o HANDLER in MySQL, consentendo un controllo più flessibile del flusso di lavoro direttamente a livello di DB.
Problema:
Gli errori possono verificarsi sia a causa di dati non corretti, sia per motivi sistemici. Se nella procedura memorizzata non è implementata la cattura e la registrazione degli errori, il debug e la manutenzione diventano estremamente difficili. Inoltre, è necessario essere in grado di distinguere tra errori critici e gestiti, in modo da non interrompere l'esecuzione dell'operazione aziendale dove non è necessario.
Soluzione:
Nei sistemi moderni, è necessario implementare costrutti per la raccolta e il logging degli errori. È necessario creare tabelle di log separate, utilizzare TRY...CATCH (SQL Server) o DECLARE ... HANDLER (MySQL), memorizzare informazioni dettagliate sulle eccezioni, in modo da poter analizzare successivamente le cause dei guasti.
Esempio di codice (SQL Server):
CREATE PROCEDURE dbo.UpdateCustomer @CustomerID INT, @NewName NVARCHAR(100) AS BEGIN BEGIN TRY UPDATE Customers SET Name = @NewName WHERE CustomerID = @CustomerID; END TRY BEGIN CATCH INSERT INTO ErrorLog (ErrorMessage, ErrorSeverity, ErrorTime) VALUES (ERROR_MESSAGE(), ERROR_SEVERITY(), GETDATE()); THROW; END CATCH END;
Caratteristiche chiave:
È possibile catturare tutti i tipi di errori all'interno di un blocco TRY...CATCH (o tramite handler)?
No, non tutti gli errori, ad esempio, i guasti gravi del server, possono essere intercettati. Errori di tipo "Attention" o guasti di connessione escono dai limiti della gestione delle transazioni.
Cosa succede alle modifiche non confermate nella procedura in caso di errore, se non si utilizza una transazione?
Le modifiche saranno parzialmente registrate, parte degli aggiornamenti entrerà nel database, mentre parte potrebbe andare persa. Per evitare incoerenze, si consiglia di utilizzare sempre transazioni.
BEGIN TRY BEGIN TRANSACTION; --...codice COMMIT; END TRY BEGIN CATCH ROLLBACK; END CATCH
È possibile utilizzare INSERT EXEC direttamente dal blocco CATCH per registrare un errore da un altro contesto?
Non sempre: INSERT EXEC è vietato in vari contesti (ad esempio, se c'è già una transazione attiva), quindi questo può generare errori di secondo livello. È meglio raccogliere i dettagli dell'errore localmente e poi registrarli con un singolo INSERT.
Il cliente ha implementato la logica solo tramite RAISERROR senza logging, quindi gli errori non venivano salvati e analizzati.
Pro:
Contro:
Utilizzato TRY...CATCH più una tabella ErrorLog, registrazione di timestamp, codice errore, utente, testo e tracciamento.
Pro:
Contro: