J'écris un script qui supprimera les enregistrements d'un certain nombre de tables, mais avant qu'il ne supprime, il doit renvoyer un nombre pour qu'un utilisateur confirme avant de valider.
Ceci est un résumé du script.
BEGIN TRANSACTION SCHEDULEDELETE
BEGIN TRY
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
PRINT 'X rows deleted. Please commit or rollback.' --calculation cut out.
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 SCHEDULEDELETE
PRINT 'Error detected, all changes reversed.'
END CATCH
--COMMIT TRANSACTION SCHEDULEDELETE --Run this if count correct.
--ROLLBACK TRANSACTION SCHEDULEDELETE --Run this if there is any doubt whatsoever.
C'est la première fois que j'écris une transaction, est-ce correct/meilleure pratique d'avoir le bloc TRY/CATCH à l'intérieur de la transaction ou la transaction doit-elle être à l'intérieur du bloc TRY?
Le facteur important dans ce script est que l'utilisateur doit valider manuellement la transaction.
Ouvrez une transaction uniquement une fois que vous êtes dans le bloc TRY
et juste avant l'instruction proprement dite, et validez-la immédiatement. N'attendez pas que votre contrôle aille à la fin du batch pour valider vos transactions.
Si quelque chose se passe mal pendant que vous êtes dans le bloc TRY
et que vous avez ouvert une transaction, le contrôle passera au bloc CATCH
. Restaurez simplement votre transaction là-bas et effectuez d'autres traitements d'erreur si nécessaire.
J'ai ajouté un petit chèque pour toute transaction ouverte en utilisant @@TRANCOUNT
fonctionne avant d'annuler réellement la transaction. Cela n'a pas vraiment de sens dans ce scénario. Il est plus utile lorsque vous effectuez des vérifications de validation dans votre bloc TRY
avant d'ouvrir une transaction, comme la vérification des valeurs de paramètres et d'autres éléments et la génération d'une erreur dans le bloc TRY
si l'une des vérifications de validation échouer. Dans ce cas, le contrôle passera au bloc CATCH
sans même ouvrir une transaction. Là, vous pouvez vérifier toute transaction ouverte et annulation s'il y en a. Dans votre cas, vous n'avez vraiment pas besoin de vérifier une transaction ouverte car vous n'entrerez pas dans le bloc CATCH
sauf si quelque chose se passe mal à l'intérieur de votre transaction.
Ne demandez pas après avoir exécuté l'opération DELETE
si elle doit être validée ou annulée; effectuez toutes ces validations avant d'ouvrir la transaction. Une fois qu'une transaction est ouverte, validez-la immédiatement et en cas d'erreur, faites le traitement des erreurs (vous faites du bon travail en obtenant des informations détaillées en utilisant presque toutes les fonctions d'erreur).
BEGIN TRY
BEGIN TRANSACTION SCHEDULEDELETE
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
COMMIT TRANSACTION SCHEDULEDELETE
PRINT 'X rows deleted. Operation Successful Tara.' --calculation cut out.
END TRY
BEGIN CATCH
IF (@@TRANCOUNT > 0)
BEGIN
ROLLBACK TRANSACTION SCHEDULEDELETE
PRINT 'Error detected, all changes reversed'
END
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
END CATCH
En plus des bons conseils de M.ALi et du doyen ci-dessus, un peu d'aide pour ceux qui cherchent à utiliser le nouveau (er) paradigme TRY CATCH THROW dans SQL SERVER:
(Je n'ai pas pu trouver facilement la syntaxe complète, alors ajoutez-la ici)
Gist: ICI
Exemple de code de procédure stockée ici (de mon Gist):
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[pr_ins_test]
@CompanyID INT
AS
SET NOCOUNT ON
BEGIN
DECLARE @PreviousConfigID INT
BEGIN TRY
BEGIN TRANSACTION MYTRAN; -- Give the transaction a name
SELECT 1/0 -- Generates divide by zero error causing control to jump into catch
PRINT '>> COMMITING'
COMMIT TRANSACTION MYTRAN;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN
PRINT '>> ROLLING BACK'
ROLLBACK TRANSACTION MYTRAN; -- The semi-colon is required (at least in SQL 2012)
END
THROW
END CATCH
END
N'attendez jamais qu'un utilisateur final valide la transaction, sauf s'il s'agit d'une base de données en mode mono-utilisateur.
En bref, il s'agit de bloquer. Votre transaction prendra des verrous exclusifs sur les ressources mises à jour et conservera ces verrous jusqu'à la fin de la transaction (validée ou annulée). Personne ne pourra toucher ces rangées. Il existe différents problèmes si l'isolement d'instantané est utilisé avec le nettoyage du magasin de versions.
Mieux vaut d'abord émettre une requête de sélection pour déterminer un certain nombre de lignes éligibles, la présenter à l'utilisateur final, et après confirmation, effectuez la suppression réelle.