Quelle est la meilleure utilisation de la gestion des erreurs SQL Server T-SQL? [fermé]

Nous avons une grande application principalement écrite dans SQL Server 7.0, où tous les appels de base de données sont des procédures stockées. nous exécutons maintenant SQL Server 2005 , qui offre plus de fonctionnalités T-SQL.

Après à peu près chaque SELECT, INSERT, UPDATE et DELETE, les erreurs @@ROWCOUNT et @@sont capturées dans des variables locales et évaluées pour détecter les problèmes. S'il y a un problème, ce qui suit est fait:

  • le paramètre de sortie du message d'erreur est défini
  • la restauration (si nécessaire) est fait
  • info est écrit (INSERT) pour enregistrer la table
  • retour avec un numéro d'erreur, unique à cette procédure (positif si fatal, négatif est avertissement)

Ils ne vérifient tous pas les lignes (seulement quand elles sont connues) et certains diffèrent avec plus ou moins d'informations de log/debug. En outre, la logique de lignes est quelque chose de séparé de la logique d'erreur (sur les mises à jour où un champ de concurrence est vérifié dans la clause WHERE, rows=0 signifie que quelqu'un d'autre a mis à jour les données). Cependant, voici un assez générique exemple:

SELECT, INSERT, UPDATE, or DELETE

SELECT @Error=@@ERROR, @Rows=@@ROWCOUNT
IF @Rows!=1 OR @Error!=0
BEGIN
    SET @ErrorMsg='ERROR 20, ' + ISNULL(OBJECT_NAME(@@PROCID), 'unknown') 
                               + ' - unable to ???????? the ????.'
    IF @@TRANCOUNT >0
    BEGIN 
        ROLLBACK
    END

    SET @LogInfo=ISNULL(@LogInfo,'')+'; '+ISNULL(@ErrorMsg,'')+
        + ' @YYYYY='        +dbo.FormatString(@YYYYY)
        +', @XXXXX='        +dbo.FormatString(@XXXXX)
        +', Error='         +dbo.FormatString(@Error)
        +', Rows='          +dbo.FormatString(@Rows)

    INSERT INTO MyLogTable (...,Message) VALUES (....,@LogInfo)

    RETURN 20

END

Je cherche à remplacer la façon dont nous le faisons avec le TRY-CATCH T-SQL. J'ai lu à propos de l'essai ...CATCH (Transact-SQL) syntaxe, alors ne publiez pas simplement un résumé de cela. Je cherche de bonnes idées et comment mieux Faire ou améliorer nos méthodes de gestion des erreurs. Il ne doit pas être Try-Catch, juste n'importe quelle bonne ou meilleure utilisation de la gestion des erreurs T-SQL.

30
demandé sur SteveC 2009-04-07 18:02:35

4 réponses

, Vous devriez lire ceci:

Http://www.sommarskog.se/error-handling-I.html

Je ne peux pas recommander ce lien assez fortement. C'est un peu long, mais dans le bon sens.

Il y a un avertissement à l'avant qu'il a été écrit à L'origine pour SQL Server 2000, mais il couvre les nouvelles capacités de gestion des erreurs try/catch dans SQL Server 2005+.

31
répondu Joel Coehoorn 2016-06-08 17:56:01

Nous utilisons actuellement Ce modèle pour toutes les requêtes que nous exécutons (vous pouvez omettre les éléments de Transaction, si vous n'en avez pas besoin dans une instruction DDL, par exemple):

BEGIN TRANSACTION
BEGIN TRY
    // do your SQL statements here

    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage

    ROLLBACK TRANSACTION
END CATCH

Bien sûr, vous pouvez facilement insérer l'exception interceptée dans votre table de journal des erreurs.

Ça marche vraiment bien pour nous. Vous pourriez probablement même automatiser une partie de la conversion de vos anciens procs stockés vers un nouveau format en utilisant la génération de Code (par exemple CodeSmith) ou un code C# personnalisé.

19
répondu marc_s 2014-07-07 09:20:59

Il n'y a pas de meilleures pratiques pour la gestion des erreurs. Tout se résume à vos besoins et cohérente.

Voici un exemple d'une table et d'une procédure stockée qui stocke les numéros de téléphone.

 SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_PADDING ON
    GO
    CREATE TABLE [dbo].[Phone](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [Phone_Type_ID] [int] NOT NULL,
        [Area_Code] [char](3) NOT NULL,
        [Exchange] [char](3) NOT NULL,
        [Number] [char](4) NOT NULL,
        [Extension] [varchar](6) NULL,
     CONSTRAINT [PK_Phone] PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    GO
    SET ANSI_PADDING OFF
    GO
    /**/

    CREATE PROCEDURE [dbo].[usp_Phone_INS]
         @Customer_ID INT
        ,@Phone_Type_ID INT
        ,@Area_Code CHAR(3)
        ,@Exchange CHAR(3)
        ,@Number CHAR(4)
        ,@Extension VARCHAR(6)
    AS
    BEGIN
        SET NOCOUNT ON;

        DECLARE @Err INT, @Phone_ID INT

        BEGIN TRY
            INSERT INTO Phone
                (Phone_Type_ID, Area_Code, Exchange, Number, Extension)
            VALUES
                (@Phone_Type_ID, @Area_Code, @Exchange, @Number, @Extension)
            SET @Err = @@ERROR
            SET @Phone_ID = SCOPE_IDENTITY()
            /* 
                Custom error handling expected by the application.
                If Err = 0 then its good or no error, if its -1 or something else then something bad happened.
            */
            SELECT ISNULL(@Err,-1) AS Err, @Phone_ID
        END TRY
        BEGIN CATCH
            IF (XACT_STATE() <> 0)
                BEGIN
                    ROLLBACK TRANSACTION
                END

            /* 
                Add your own custom error handling here to return the passed in paramters. 
                I have removed my custom error halding code that deals with returning the passed in parameter values.
            */

            SELECT ERROR_NUMBER() AS Err, ISNULL(@Phone_ID,-1) AS ID
        END CATCH
    END
6
répondu DBAndrew 2009-04-07 15:25:16

Il semble que vous ayez déjà une très bonne maîtrise de cela. Je soupçonne que vous faites plus de 95% des programmeurs SQL là-bas.

, Vous devriez trouver quelques informations intéressantes ici:

Une suggestion [sans rapport]: commencez à utiliser ' ' au lieu de '!='.

[*SQL Junkies a disparu, donc le deuxième article n'est pas disponible. Je vais essayer de le republier quelque part et mettre à jour le lien.]

3
répondu Rob Garrison 2009-09-30 17:53:42