J'ai une procédure stockée qui n'exécute que 3 procédures stockées à l'intérieur. J'utilise seulement 1 paramètre pour stocker si le SP maître est réussi.
Si la première procédure stockée fonctionne correctement dans la procédure stockée principale, mais que la 2ème procédure stockée échoue, est-ce qu'elle annulera automatiquement tous les SP dans le SP maître ou dois-je effectuer une commande?
Voici ma procédure:
CREATE PROCEDURE [dbo].[spSavesomename]
-- Add the parameters for the stored procedure here
@successful bit = null output
AS
BEGIN
begin transaction createSavebillinginvoice
begin Try
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN
EXEC [dbo].[spNewBilling1]
END
BEGIN
EXEC [dbo].[spNewBilling2]
END
BEGIN
EXEC [dbo].[spNewBilling3]
END
set @successful = 1
end Try
begin Catch
rollback transaction createSavesomename
insert into dbo.tblErrorMessage(spName, errorMessage, systemDate)
values ('spSavesomename', ERROR_MESSAGE(), getdate())
return
end Catch
commit transaction createSavesomename
return
END
GO
sql-server
stored-procedures
transaction
user2483342
la source
la source
spNewBilling3
renvoie une erreur, mais que vous ne souhaitez pas revenir en arrièrespNewBilling2
ouspNewBilling1
, supprimez simplement[begin|rollback|commit] transaction createSavebillinginvoice
despSavesomename
.Réponses:
Étant donné uniquement le code indiqué dans la question, et en supposant qu'aucun des trois sous-procs n'a de gestion de transaction explicite, alors oui, une erreur dans l'un des trois sous-procs sera détectée et
ROLLBACK
leCATCH
bloc bloquera tous du travail.MAIS voici quelques points à noter sur les transactions (au moins dans SQL Server):
Il n'y a qu'une seule transaction réelle (la première), peu importe le nombre de fois que vous appelez
BEGIN TRAN
BEGIN TRAN
, qu'il soit nommé ou non, le compteur de transactions est incrémenté de 1.SELECT @@TRANCOUNT;
COMMIT
commandes émises quand@@TRANCOUNT
est à 2 ou plus ne font que réduire, un à la fois, le compteur de transactions.COMMIT
soit émis lorsque le@@TRANCOUNT
est à1
Les points de sauvegarde permettent de créer un sous-ensemble de travail dans la transaction qui peut être annulé.
SAVE TRAN {save_point_name}
commandeROLLBACK {save_point_name}
. (plus d'informations ci-dessous)SAVE TRAN {save_point_name}
, y compris tous les points de sauvegarde créés après la création de celui qui a été annulé (d'où l'imbrication).SAVE TRAN
ne peut être annulé, sauf en émettant un pleinROLLBACK
de la transaction entière.COMMIT
quand@@TRANCOUNT
est à 2 ou plus, n'a aucun effet sur les points de sauvegarde (car encore une fois, les niveaux de transaction supérieurs à 1 n'existent pas en dehors de ce compteur).Vous ne pouvez pas valider des transactions nommées spécifiques. La transaction "nom", si elle est fournie avec le
COMMIT
, est ignorée et n'existe que pour la lisibilité.Une
ROLLBACK
émission sans nom annulera toujours TOUTES les transactions.Un titre
ROLLBACK
délivré doit correspondre à:supposant qu'aucun
SAVE TRAN
n'a été appelé avec le même nom de transaction, cela annulera TOUTES les transactions.ce comportement "annulera" toutes les modifications apportées depuis l' appel du plus récent
SAVE TRAN {save_point_name}
.SAVE TRAN
commandes avec son nom, alors chaque ROLLBACK de ce nom de transaction annulera chaque point de sauvegarde jusqu'à ce qu'il n'en reste plus. Après cela, un ROLLBACK émis de ce nom annulera TOUTES les transactions.Par exemple, supposons que les commandes suivantes ont été exécutées dans l'ordre indiqué:
Maintenant, si vous émettez (chacun des scénarios suivants est indépendant les uns des autres):
ROLLBACK TRAN B
une fois: il annulera "DML Query 4".@@TRANCOUNT
est toujours 2.ROLLBACK TRAN B
deux fois: cela annulera "DML Query 4" puis une erreur car il n'y a pas de point de sauvegarde correspondant pour "B".@@TRANCOUNT
est toujours 2.ROLLBACK TRAN A
une fois: il annulera "DML Query 4" et "DML Query 3".@@TRANCOUNT
est toujours 2.ROLLBACK TRAN A
deux fois: il annulera "DML Query 4", "DML Query 3" et "DML Query 2".@@TRANCOUNT
est toujours 2.ROLLBACK TRAN A
trois fois: il annulera "DML Query 4", "DML Query 3" et "DML Query 2". Ensuite, il annulera l'intégralité de la transaction (il ne restait plus que "DML Query 1").@@TRANCOUNT
est maintenant 0.COMMIT
une fois:@@TRANCOUNT
descend à 1.COMMIT
une fois et puisROLLBACK TRAN B
une fois:@@TRANCOUNT
descend à 1. Ensuite, il annulera "DML Query 4" (prouvant que COMMIT n'a rien fait).@@TRANCOUNT
est toujours 1.Noms des transactions et noms des points d'enregistrement:
Une procédure stockée n'est pas, en soi, une transaction implicite. Chaque requête, si aucune transaction explicite n'a été démarrée, est une transaction implicite. C'est pourquoi les transactions explicites autour de requêtes uniques ne sont pas nécessaires, sauf s'il peut y avoir une raison programmatique de le faire
ROLLBACK
, sinon toute erreur dans la requête est une restauration automatique de cette requête.Lors de l'appel d'une procédure stockée, elle doit quitter avec la valeur d'
@@TRANCOUNT
être la même que lorsqu'elle a été appelée. Vous ne pouvez donc pas:BEGIN TRAN
dans le proc sans le valider, en attendant de le valider dans le processus appelant / parent.ROLLBACK
si une transaction explicite a été lancée avant l'appel du proc car elle reviendra@@TRANCOUNT
à 0.Si vous quittez une procédure stockée avec un nombre de transactions supérieur ou inférieur à celui où elle a démarré, vous obtiendrez une erreur similaire à:
Les variables de table, tout comme les variables régulières, ne sont pas liées par des transactions.
En ce qui concerne la gestion des transactions dans les procs qui peut être appelée indépendamment (et donc avoir besoin de la gestion des transactions) ou appeler à partir d'autres procs (donc pas besoin de la gestion des transactions): cela peut être accompli de deux manières différentes.
La façon dont je le manipule depuis plusieurs années maintenant qui semble bien fonctionner est de n'utiliser que
BEGIN
/COMMIT
/ROLLBACK
sur la couche la plus externe. Les appels sous-proc ignorent simplement les commandes de transaction. J'ai décrit ci-dessous ce que je mets dans chaque proc (enfin, chacun qui nécessite une gestion de transaction).DECLARE @InNestedTransaction BIT;
Au lieu de simple
BEGIN TRAN
, faites:Au lieu de simple
COMMIT
, faites:Au lieu de simple
ROLLBACK
, faites:Cette méthode doit fonctionner de la même manière, que la transaction ait été démarrée dans SQL Server ou qu'elle ait été lancée au niveau de la couche d'application.
Pour le modèle complet de cette gestion des transactions dans la
TRY...CATCH
construction, veuillez consulter ma réponse à la question DBA.SE suivante: sommes-nous tenus de gérer les transactions en code C # ainsi qu'en procédure stockée .Au-delà des "bases", il y a quelques nuances supplémentaires à prendre en compte:
Par défaut, les transactions ne sont, la plupart du temps, pas automatiquement annulées / annulées lorsqu'une erreur se produit. Ce n'est généralement pas un problème tant que vous gérez correctement les erreurs et appelez-
ROLLBACK
vous. Cependant, parfois les choses se compliquent, comme dans le cas d'erreurs d'abandon par lots, ou lors de l'utilisationOPENQUERY
(ou des serveurs liés en général) et une erreur se produit sur le système distant. Alors que la plupart des erreurs peuvent être piégées en utilisantTRY...CATCH
, il y en a deux qui ne peuvent pas être piégées de cette façon (cependant, je ne me souviens pas lesquelles pour le moment - recherche). Dans ces cas, vous devez utiliserSET XACT_ABORT ON
pour annuler correctement la transaction.SET XACT_ABORT ON fait que SQL Server annule immédiatement toute transaction (si une est active) et abandonne le lot si une erreur se produit. Ce paramètre existait avant SQL Server 2005, qui a introduit la
TRY...CATCH
construction. Pour la plupart,TRY...CATCH
gère la plupart des situations et rend donc la plupart du temps obsolèteXACT_ABORT ON
. Cependant, lors de l'utilisationOPENQUERY
(et éventuellement d'un autre scénario dont je ne me souviens pas pour le moment), vous devrez toujours l'utiliserSET XACT_ABORT ON;
.À l'intérieur d'un déclencheur,
XACT_ABORT
est implicitement défini surON
. Cela provoque toute erreur dans le déclencheur pour annuler l'intégralité de l'instruction DML qui a déclenché le déclencheur.Vous devez toujours avoir une gestion des erreurs appropriée, en particulier lorsque vous utilisez des transactions. La
TRY...CATCH
construction, introduite dans SQL Server 2005, fournit un moyen de gérer presque toutes les situations, une amélioration bienvenue par rapport aux tests@@ERROR
après chaque instruction, ce qui n'a pas beaucoup aidé avec les erreurs d'abandon de lot.TRY...CATCH
introduit un nouvel «État». Lorsque vous n'utilisez pas laTRY...CATCH
construction, si vous avez une transaction active et qu'une erreur se produit, plusieurs chemins peuvent être empruntés:XACT_ABORT OFF
et erreur d'abandon de l'instruction: la transaction est toujours active et le traitement se poursuit avec l' instruction suivante , le cas échéant.XACT_ABORT OFF
et la plupart des erreurs d'abandon de lot: la transaction est toujours active et le traitement se poursuit avec le lot suivant , le cas échéant.XACT_ABORT OFF
et certaines erreurs d'abandon de lot: la transaction est annulée et le traitement se poursuit avec le lot suivant , le cas échéant.XACT_ABORT ON
et toute erreur: la transaction est annulée et le traitement se poursuit avec le lot suivant , le cas échéant.TOUTEFOIS, lors de l'utilisation
TRY...CATCH
, les erreurs d'abandon de lot n'interrompent pas le lot, mais transfèrent plutôt le contrôle auCATCH
bloc. LorsqueXACT_ABORT
c'est le casOFF
, la transaction sera toujours active la grande majorité du temps, et vous devrezCOMMIT
, ou très probablement, le faireROLLBACK
. Mais lorsque vous rencontrez certaines erreurs d'abandon de lot (comme avecOPENQUERY
), ou quandXACT_ABORT
c'est le casON
, la transaction sera dans un nouvel état, "non engageable". Dans cet état, vous ne pouvezCOMMIT
ni ne pouvez effectuer aucune opération DML. Tout ce que vous pouvez faire estROLLBACK
etSELECT
déclarations. Cependant, dans cet état "incontrôlable", la transaction a été annulée lors de l'erreur qui s'est produite, et l'émission de laROLLBACK
est juste une formalité, mais celle qui doit être effectuée.Une fonction, XACT_STATE , peut être utilisée pour déterminer si une transaction est active, non engageable ou n'existe pas. Il est recommandé (par certains, au moins) de vérifier cette fonction dans le
CATCH
bloc pour déterminer si le résultat est-1
(c'est-à-dire non engageable) au lieu de tester si@@TRANCOUNT > 0
. Mais avecXACT_ABORT ON
, cela devrait être le seul état possible, il semble donc que les tests pour@@TRANCOUNT > 0
etXACT_STATE() <> 0
soient équivalents. D'un autre côté, quandXACT_ABORT
estOFF
et qu'il y a une Transaction active, alors il est possible d'avoir un état de1
ou-1
dans leCATCH
bloc, ce qui permet la possibilité d'émettre à laCOMMIT
place deROLLBACK
(bien que, je ne puisse pas penser à un cas où quelqu'un voudraitCOMMIT
si la transaction est validable). Vous trouverez plus d'informations et de recherches sur l'utilisationXACT_STATE()
dans unCATCH
bloc avecXACT_ABORT ON
dans ma réponse à la question DBA.SE suivante: dans quels cas une transaction peut-elle être validée depuis l'intérieur du bloc CATCH lorsque XACT_ABORT est défini sur ON? . Veuillez noter qu'il existe un bogue mineurXACT_STATE()
qui le fait renvoyer à tort1
dans certains scénarios: XACT_STATE () renvoie 1 lorsqu'il est utilisé dans SELECT avec certaines variables système mais sans clause FROMRemarques sur le code d'origine:
BEGIN
etEND
autour de chaqueEXEC
appella source
Compile errors, such as syntax errors, that prevent a batch from running
etErrors that occur during statement-level recompilation, such as object name resolution errors that occur after compilation because of deferred name resolution.
. Mais ils ne se produisent pas très souvent, et lorsque vous trouvez une telle situation, corrigez-la (s'il s'agit d'un bogue dans le code) ou placez-la dans un sous-processus (EXEC
ousp_executesql
) afin qu'elleTRY...CATCH
puisse la piéger.Oui, si en raison d'une erreur de code d'annulation dans l'instruction catch de votre procédure stockée principale, elle s'exécutera, elle annulera toutes les opérations effectuées par n'importe quelle instruction directe ou via l'une de vos procédures stockées imbriquées.
Même si vous n'avez appliqué aucune transaction explicite dans vos procédures stockées imbriquées, ces procédures stockées utiliseront une transaction implicite et seront validées à la fin MAIS soit vous avez effectué une transaction explicite ou implicite dans des procédures stockées imbriquées, le moteur SQL Server l'ignorera et le fera annule toutes les actions de ces procédures stockées imbriquées si la procédure stockée principale échoue et que la transaction est annulée.
Chaque fois que la transaction est validée ou annulée en fonction de l'action effectuée à la fin de la transaction la plus externe. Si la transaction externe est validée, les transactions internes imbriquées sont également validées. Si la transaction externe est annulée, toutes les transactions internes sont également annulées, que les transactions internes aient été ou non validées individuellement.
Pour référence http://technet.microsoft.com/en-us/library/ms189336(v=sql.105).aspx
la source