Le traitement des erreurs et l'organisation de la journalisation en SQL ont acquis une popularité particulière avec le développement de processus métier complexes, lorsque il est devenu important non seulement d'arrêter l'exécution en cas d'erreur, mais aussi de consigner le fait d'un échec et, si possible, de continuer à travailler. À l'origine, SQL ne possédait pas de mécanismes avancés de try-catch, et chaque SGBD proposait ses propres mécanismes.
Historique de la question :
Les premières versions des normes SQL n'avaient pas d'opérateurs intégrés pour capturer les erreurs dans les procédures. Plus tard, les fabricants ont commencé à mettre en œuvre des constructions telles que TRY...CATCH dans Microsoft SQL Server ou HANDLER dans MySQL, permettant un contrôle plus flexible du flux de travail directement au niveau de la base de données.
Problème :
Les erreurs peuvent survenir en raison de données incorrectes ou pour des raisons systémiques. Si la procédure stockée n'implémente pas la capture et l'enregistrement des erreurs, le débogage et la maintenance deviennent extrêmement difficiles. De plus, il est nécessaire de pouvoir distinguer les erreurs critiques des erreurs gérées, afin de ne pas interrompre l'exécution des opérations métier là où cela n'est pas nécessaire.
Solution :
Dans les systèmes modernes, il est conseillé d'implémenter des constructions de collecte et de journalisation des erreurs. Il faut créer des tables de journalisation séparées, utiliser TRY...CATCH (SQL Server) ou DECLARE ... HANDLER (MySQL), conserver des informations détaillées sur les exceptions afin d'analyser ensuite les causes des pannes.
Exemple de code (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;
Caractéristiques clés :
Tous les types d'erreurs peuvent-ils être capturés à l'intérieur du bloc TRY...CATCH (ou via un handler) ?
Non, toutes les erreurs, par exemple, les pannes graves du serveur, ne peuvent pas être interceptées. Les erreurs de type "Attention," ou l'échec de la connexion échappent au traitement transactionnel.
Que se passera-t-il avec les modifications non validées dans la procédure en cas d'erreur, si aucune transaction n’est utilisée ?
Les modifications seront partiellement validées, une partie des mises à jour sera intégrée à la base, et une partie pourrait être perdue. Pour éviter une incohérence, il est recommandé d'utiliser toujours des transactions.
BEGIN TRY BEGIN TRANSACTION; --...code COMMIT; END TRY BEGIN CATCH ROLLBACK; END CATCH
Peut-on utiliser INSERT EXEC directement depuis le bloc CATCH pour enregistrer une erreur à partir d'un autre contexte ?
Pas toujours : INSERT EXEC est interdit dans certains contextes (par exemple, s'il y a déjà une transaction active), ce qui peut entraîner des erreurs de second niveau. Il est préférable de collecter les détails de l'erreur localement et de les enregistrer ensuite via un INSERT unique.
Le client a implémenté la logique uniquement via RAISERROR sans journalisation, donc les erreurs n'étaient pas conservées ni analysées.
Avantages :
Inconvénients :
Utilisation de TRY...CATCH plus la table ErrorLog, consignation de l'heure, du code d'erreur, de l'utilisateur, du texte et de la trace.
Avantages :
Inconvénients :