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'utilisation OPENQUERY
(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 utilisant TRY...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 utiliser SET 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ète XACT_ABORT ON
. Cependant, lors de l'utilisation OPENQUERY
(et éventuellement d'un autre scénario dont je ne me souviens pas pour le moment), vous devrez toujours l'utiliser SET XACT_ABORT ON;
.
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 la TRY...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 au CATCH
bloc. Lorsque XACT_ABORT
c'est le cas OFF
, la transaction sera toujours active la grande majorité du temps, et vous devrez COMMIT
, ou très probablement, le faire ROLLBACK
. Mais lorsque vous rencontrez certaines erreurs d'abandon de lot (comme avec OPENQUERY
), ou quand XACT_ABORT
c'est le cas ON
, la transaction sera dans un nouvel état, "non engageable". Dans cet état, vous ne pouvez COMMIT
ni ne pouvez effectuer aucune opération DML. Tout ce que vous pouvez faire est ROLLBACK
et SELECT
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 la ROLLBACK
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 avec XACT_ABORT ON
, cela devrait être le seul état possible, il semble donc que les tests pour @@TRANCOUNT > 0
et XACT_STATE() <> 0
soient équivalents. D'un autre côté, quand XACT_ABORT
est OFF
et qu'il y a une Transaction active, alors il est possible d'avoir un état de 1
ou -1
dans le CATCH
bloc, ce qui permet la possibilité d'émettre à la COMMIT
place de ROLLBACK
(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'utilisation XACT_STATE()
dans un CATCH
bloc avec XACT_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 mineur XACT_STATE()
qui le fait renvoyer à tort 1
dans certains scénarios: XACT_STATE () renvoie 1 lorsqu'il est utilisé dans SELECT avec certaines variables système mais sans clause FROM
spNewBilling3
renvoie une erreur, mais que vous ne souhaitez pas revenir en arrièrespNewBilling2
ouspNewBilling1
, supprimez simplement[begin|rollback|commit] transaction createSavebillinginvoice
despSavesomename
.