Implémenter la gestion des exceptions structurées

Terminée

Maintenant que vous avez une compréhension de la nature des erreurs et de la gestion des erreurs de base dans T-SQL, il est temps d’examiner une forme plus avancée de gestion des erreurs : gestion structurée des exceptions.

Ici, vous verrez comment l’utiliser et évaluer ses avantages et ses limitations, notamment le bloc TRY CATCH, le rôle des fonctions de gestion des erreurs et comprendre la différence entre les erreurs interceptables et noncatchables. Enfin, vous verrez comment les erreurs peuvent être gérées et exposées si nécessaire.

Présentation de la programmation de blocs TRY/CATCH

La gestion structurée des exceptions est plus puissante que la gestion des erreurs basée sur la @@ERROR variable système. Il vous permet d’empêcher le code d’être litté avec le code de gestion des erreurs et de centraliser ce code de gestion des erreurs. La centralisation du code de gestion des erreurs signifie également que vous pouvez vous concentrer davantage sur l’objectif du code plutôt que sur la gestion des erreurs qu’il contient.

Bloc TRY et bloc CATCH

Lorsque vous utilisez la gestion des exceptions structurées, le code susceptible de déclencher une erreur est placé dans un bloc TRY. Les blocs TRY sont placés BEGIN TRY entre les instructions et END TRY les instructions.

Si une erreur interceptable se produit : la plupart des erreurs peuvent être interceptées, le contrôle d’exécution passe au bloc CATCH. Le bloc CATCH est une série d’instructions T-SQL placées entre BEGIN CATCH les instructions et END CATCH les instructions.

Remarque

Bien qu’il BEGIN CATCH s’agit d’instructions END TRY distinctes, il BEGIN CATCH doit immédiatement suivre le END TRY.

Limitations actuelles

Les langages de haut niveau offrent souvent une construction try/catch/finally et sont souvent utilisés pour libérer implicitement des ressources. Il n’existe aucun bloc FINALLY équivalent dans T-SQL.

Comprendre la différence entre les erreurs interceptables et noncatchables

Il est important de se rendre compte que, tandis que les blocs TRY/CATCH vous permettent d’intercepter une plage d’erreurs beaucoup plus large que possible @@ERROR, vous ne pouvez pas intercepter chaque type.

Erreurs interceptables et noncatchables

Toutes les erreurs ne peuvent pas être interceptées par des blocs TRY/CATCH dans la même étendue que celle du bloc TRY/CATCH. Souvent, les erreurs qui ne peuvent pas être interceptées dans la même étendue peuvent être interceptées dans une étendue environnante. Par exemple, vous ne pourrez peut-être pas intercepter une erreur dans la procédure stockée qui contient le bloc TRY/CATCH. Toutefois, vous êtes susceptible d’intercepter cette erreur dans un bloc TRY/CATCH dans le code qui a appelé la procédure stockée où l’erreur s’est produite.

Erreurs non modifiables courantes

Certaines erreurs ne sont jamais interceptées TRY/CATCH dans n’importe quelle étendue :

  • Messages ou avertissements d’information avec gravité 10 ou inférieure.
  • Erreurs avec gravité 20 ou supérieure qui arrêtent la tâche Moteur de base de données SQL Server pour la session.
  • Attentions : demandes d’interruption du client ou connexions client interrompues.
  • Sessions terminées par un administrateur système à l’aide KILLde .

D’autres erreurs ne sont pas interceptées dans la même étendue que celle TRY/CATCH qui existe, mais peuvent être interceptées par une TRY/CATCH étendue environnante (par exemple, dans le lot appelant ou la procédure stockée) :

  • Erreurs de compilation, telles que les erreurs de syntaxe, qui empêchent la compilation d’un lot.
  • Erreurs de résolution de noms d’objet provoquées par la résolution de noms différée, par exemple une procédure stockée qui fait référence à une table qui n’existe pas encore. L’erreur est levée uniquement lorsque la procédure tente de résoudre le nom au moment de l’exécution.

Comment recréer des erreurs à l’aide de THROW

Si l’instruction THROW est utilisée dans un bloc CATCH sans aucun paramètre, l’erreur a provoqué l’entrée du code dans le bloc CATCH. Vous pouvez utiliser cette technique pour implémenter la journalisation des erreurs dans la base de données en interceptant les erreurs et en journalisant leurs détails, puis en lisant l’erreur d’origine dans l’application cliente, afin qu’elle puisse être gérée là-bas.

Voici un exemple de réexécriture d’une erreur.

BEGIN TRY
    -- code to be executed
END TRY
BEGIN CATCH
    PRINT ERROR_MESSAGE();
    THROW
END CATCH

Dans certaines versions antérieures de SQL Server, aucune méthode n’a été utilisée pour lever une erreur système. Bien que THROW vous ne puissiez pas spécifier d’erreur système à déclencher, lorsqu’elle THROW est utilisée sans paramètres dans un bloc CATCH, elle réexécise les erreurs système et utilisateur.

Qu’est-ce que les fonctions de gestion des erreurs ?

Les blocs CATCH rendent les informations liées à l’erreur disponibles tout au long de la durée du bloc CATCH. Cela inclut des sous-étendues, telles que des procédures stockées, exécutées à partir du bloc CATCH.

Fonctions de gestion des erreurs

Rappelez-vous que, lors de la programmation avec @@ERROR, la valeur détenue par la @@ERROR variable système a été réinitialisée dès que l’instruction suivante a été exécutée.

Un autre avantage clé de la gestion structurée des exceptions dans T-SQL est qu’une série de fonctions de gestion des erreurs a été fournie et qu’elles conservent leurs valeurs dans tout le bloc CATCH. Les fonctions distinctes fournissent chaque propriété d’une erreur qui a été générée.

Cela signifie que vous pouvez écrire des procédures stockées de gestion des erreurs génériques qui peuvent toujours accéder aux informations relatives aux erreurs.

  • Les blocs CATCH rendent les informations liées à l’erreur disponibles tout au long de la durée du bloc CATCH.
  • @@Error est réinitialisé lorsque l’instruction suivante est exécutée.

Gérer les transactions dans les blocs CATCH

Une erreur qui met normalement fin à une transaction en dehors d’un TRY bloc peut laisser la transaction dans un état noncommittable lorsque l’erreur se produit à l’intérieur d’un TRY bloc. Une transaction noncommittable ne peut effectuer que des opérations de lecture ou une ROLLBACK TRANSACTIONtentative de validation ou de modification des données génère une autre erreur.

Utilisez la XACT_STATE() fonction à l’intérieur CATCH des blocs pour déterminer ce qu’il faut faire avec la transaction actuelle :

  • XACT_STATE() = 1 — il existe une transaction active et valide. Vous pouvez COMMIT ou ROLLBACK.
  • XACT_STATE() = 0 — il n’y a pas de transaction active. Aucune validation ou restauration n’est requise.
  • XACT_STATE() = -1 — il existe une transaction active mais noncommittable. Vous devez ROLLBACK; la validation échoue.

@@TRANCOUNT seul ne peut pas détecter l’état noncommittable. Il s’agit donc XACT_STATE() de la vérification recommandée pour les blocs CATCH qui gèrent les transactions.

Le modèle de bloc CATCH canonique est le suivant :

BEGIN CATCH
    IF XACT_STATE() = -1
        ROLLBACK TRANSACTION;
    ELSE IF XACT_STATE() = 1
        COMMIT TRANSACTION;  -- or ROLLBACK, depending on intent

    THROW;  -- rethrow to caller
END CATCH;

Gérer les erreurs dans le code

L’intégration de SQL CLR permet l’exécution du code managé dans SQL Server. Les langages .NET de haut niveau, tels que C# et VB, ont une gestion détaillée des exceptions à leur disposition. Les erreurs peuvent être interceptées à l’aide des blocs .NET standard try/catch/finally.

Erreurs dans le code managé

En général, vous souhaiterez peut-être intercepter les erreurs dans le code managé autant que possible. Il est important de réaliser, cependant, que toutes les erreurs non gérées dans le code managé sont passées au code T-SQL appelant. Chaque fois qu’une erreur se produit dans le code managé est retournée à SQL Server, il semble qu’il s’agit d’une erreur 6522. Les erreurs peuvent être imbriquées et cette erreur particulière est encapsulée à la cause réelle de l’erreur.

Une autre cause rare mais possible d’erreurs dans le code managé serait que le code pourrait exécuter une RAISERROR instruction T-SQL via un objet SqlCommand.