Nous avons une grande application principalement écrite en SQL Server 7.0, où tous les appels de base de données sont vers 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 tous les SELECT, INSERT, UPDATE et DELETE, les @@ ROWCOUNT et @@ ERROR sont capturés dans des variables locales et évalués pour les problèmes. En cas de problème, procédez comme suit:
Ils ne vérifient pas tous les lignes (uniquement lorsque cela est connu) et certains diffèrent avec plus ou moins d'informations de journal/débogage. En outre, la logique des lignes est parfois séparée de la logique d'erreur (sur les mises à jour où un champ d'accès simultané est vérifié dans la clause WHERE, lignes = 0 signifie que quelqu'un d'autre a mis à jour les données). Cependant, voici un exemple assez générique:
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 la syntaxe TRY ... CATCH (Transact-SQL) , alors ne postez pas simplement un résumé de cela. Je suis à la recherche de bonnes idées et de la meilleure façon de faire ou d'améliorer nos méthodes de gestion des erreurs. Il ne doit pas nécessairement s'agir de Try-Catch, mais de toute bonne ou meilleure utilisation de la gestion des erreurs T-SQL.
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 également les nouvelles capacités de gestion des erreurs try/catch dans SQL Server 2005+.
Nous utilisons actuellement ce modèle pour toutes les requêtes que nous exécutons (vous pouvez laisser de côté le truc Transaction, si vous n'en avez pas besoin, par exemple dans une instruction DDL):
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.
Cela fonctionne vraiment bien pour nous. Vous pourriez probablement même automatiser une partie de la conversion de vos anciens processus stockés vers un nouveau format en utilisant la génération de code (par exemple CodeSmith) ou du code C # personnalisé.
Il n'y a pas de meilleures pratiques en matière de gestion des erreurs. Tout dépend de vos besoins et de votre cohérence.
Voici un exemple de table et de 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
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.
Vous devriez trouver des informations intéressantes ici:
Une suggestion [non liée]: commencez à utiliser '<>' au lieu de '! ='.
[* SQL Junkies a disparu, le deuxième article n'est donc pas disponible. Je vais essayer de le republier quelque part et de mettre à jour le lien.]