N'utilisez pas de transaction pour la procédure stockée
18
J'ai une procédure stockée qui exécute quelques commandes. Je ne veux pas que ces commandes soient incluses dans la transaction de la procédure stockée. Si la 4ème commande échoue, je veux que les 1ère, 2ème et 3ème restent et non pas revenir en arrière.
Est-il possible d'écrire la procédure stockée de telle manière qu'elle ne s'exécute pas toutes en une seule grosse transaction?
Toutes les transactions ne s'exécuteront pas en une seule transaction. Jetez un œil à cet exemple:
use TestDB;
go
ifexists(select1from sys.tables where object_id = object_id('dbo.TestTranTable1'))droptable dbo.TestTranTable1;createtable dbo.TestTranTable1
(
id int identity(1,1)notnull,
some_int int notnulldefault1);
go
insertinto dbo.TestTranTable1
defaultvalues;
go 4select*from dbo.TestTranTable1;ifexists(select1from sys.sql_modules where object_id = object_id('dbo.ChangeValues'))begindropproc dbo.ChangeValues;end
go
createproc dbo.ChangeValues
asupdate dbo.TestTranTable1
set some_int =11where id =1;update dbo.TestTranTable1
set some_int =12where id =2;update dbo.TestTranTable1
set some_int =13where id =3;-- this will error out (arithmetic overflow)update dbo.TestTranTable1
set some_int =2147483648where id =4;
go
exec dbo.ChangeValues;select*from dbo.TestTranTable1;
Voici la sortie:
En créant une session d'événements étendus pour surveiller l' sql_transactionévénement, voici la sortie de l'exécution dbo.ChangeValues:
Comme vous pouvez le voir dans cette capture d'écran ci-dessus, il existe des transactions distinctes pour chacun des quatre relevés. Les 3 premiers commit, et le dernier annule à cause de l'erreur.
Je pense qu'il peut y avoir une certaine confusion ici à propos d'un lot par rapport à une transaction .
Une transaction est une instruction ou un ensemble d'instructions qui réussiront ou échoueront en tant qu'unité. Toutes les instructions DDL sont dans les transactions elles-mêmes (c'est-à-dire que si vous mettez à jour 100 lignes mais que la ligne 98 renvoie une erreur, aucune des lignes n'est mise à jour). Vous pouvez également encapsuler une série d'instructions dans une transaction en utilisant BEGIN TRANSACTIONpuis ou COMMITou ROLLBACK.
Un lot est une série d'instructions qui sont exécutées ensemble. Une procédure stockée est un exemple de lot. Dans une procédure stockée, si une instruction échoue et qu'il y a interception d'erreur (normalement des TRY/CATCHblocs), les instructions suivantes ne s'exécuteront pas.
Je soupçonne que votre problème est que le lot est annulé lorsqu'une erreur se produit car le processus stocké lui-même ou une étendue externe (comme l'application ou le processus stocké qui appelle cette procédure) contient une erreur de récupération. Si tel est le cas, cela est plus difficile à résoudre car vous devez ajuster la façon dont vous gérez les erreurs quelle que soit la portée qui les intercepte.
Je n'ai trouvé aucun article disant: "Une procédure de stockage est un exemple de lot". Je pense que la procédure stockée est très similaire au lot, mais ce n'est pas un lot. La principale différence est que SP est garanti d'être compilé à l'avance et prêt à être exécuté plusieurs fois contrairement aux lots. Les similitudes sont les suivantes: - Ils exécutent tous les deux chaque commande à la fois. - Si une commande a échoué, toutes les commandes précédentes sont validées (sauf si elle était en cours d'exécution dans une transaction) - si une commande a échoué, toutes les commandes suivantes ne sont pas exécutées.
Ashi
6
Tout dans le serveur SQL est contenu dans une transaction.
Lorsque vous spécifiez explicitement begin transactionet que end transactioncela s'appelle Transaction explicite . Dans le cas contraire, il s'agit d'une transaction implicite .
Pour changer le mode dans lequel vous vous trouvez, vous utiliseriez
set implicit_transactions on
ou
set implicit_transactions offselect@@OPTIONS &2
si ci-dessus renvoie 2, vous êtes en mode de transaction implicite. S'il renvoie 0, vous êtes en autocommit.
Une transaction est TOUT ou rien pour garder la base de données dans un état cohérent. N'oubliez pas les propriétés ACID.
C'est ainsi que les procédures stockées fonctionnent par défaut. La procédure stockée n'est pas automatiquement incluse dans une transaction.
Si vous voulez que la procédure stockée s'arrête lorsqu'elle rencontre la première erreur, vous voudrez y mettre une connexion TRY / CATCH pour revenir en cas de problème avec la commande 2 par exemple.
Je veux qualifier cette transaction individuelle de comportement par défaut pour les procédures stockées, car toutes les instructions sont encapsulées dans des transactions implicites; cependant, personne ne devrait s'appuyer sur des transactions implicites pour contrôler le destin de son code. Il est préférable de contrôler explicitement la façon dont les transactions sont traitées dans le code de production.
séparez chacune des pièces avec un BEGIN TRAN et vérifiez si la transaction a réussi. s'il a été validé, sinon faites une restauration, car ils s'exécutent tous à partir du même niveau, vous pourrez valider chaque section séparément sans avoir à tout restaurer en cas d'échec.
Cela créera-t-il des sous-transactions dans ma procédure stockée? Idéalement, j'aimerais éviter cela si possible
Matthew Steeples
1
Si le SP est appelé à partir d'une transaction, les transactions enregistrées ci-dessus sont la réponse. Si le sp n'est pas appelé avec, alors @mrdenny est correct. Le serveur SQL ne prend pas en charge les transactions imbriquées.
Pour être clair (et pour les paresseux qui ne veulent pas cliquer sur les liens), vous ne démarrez pas réellement une autre transaction. Aka le titre sur le post de Paul: "Mythe: les transactions imbriquées sont réelles." Ce ne sont pas de vraies transactions. COMMIT dans une transaction imbriquée ne fait rien d'autre que décrémenter @@ TRANCOUNT. Il est vrai que vous n'obtenez pas d'erreur si vous imbriquez BEGIN TRAN / COMMIT, mais c'est différent d'avoir de vraies transitions imbriquées.
Tout dans le serveur SQL est contenu dans une transaction.
Lorsque vous spécifiez explicitement
begin transaction
et queend transaction
cela s'appelle Transaction explicite . Dans le cas contraire, il s'agit d'une transaction implicite .Pour changer le mode dans lequel vous vous trouvez, vous utiliseriez
ou
si ci-dessus renvoie 2, vous êtes en mode de transaction implicite. S'il renvoie 0, vous êtes en autocommit.
Une transaction est TOUT ou rien pour garder la base de données dans un état cohérent. N'oubliez pas les propriétés ACID.
- créez le SP maintenant - notez que les 3 premiers réussiront et que le 4ème échouera en raison de la troncature des chaînes ...
Voir: Est-ce une mauvaise pratique de toujours créer une transaction?
la source
C'est ainsi que les procédures stockées fonctionnent par défaut. La procédure stockée n'est pas automatiquement incluse dans une transaction.
Si vous voulez que la procédure stockée s'arrête lorsqu'elle rencontre la première erreur, vous voudrez y mettre une connexion TRY / CATCH pour revenir en cas de problème avec la commande 2 par exemple.
la source
Vous aurez besoin de transactions individuelles pour chaque commande. Vous pouvez également accomplir cela avec des transactions enregistrées:
Voir
SAVE TRANSACTION (Transact-SQL)
dans la documentation du produit.Je veux qualifier cette transaction individuelle de comportement par défaut pour les procédures stockées, car toutes les instructions sont encapsulées dans des transactions implicites; cependant, personne ne devrait s'appuyer sur des transactions implicites pour contrôler le destin de son code. Il est préférable de contrôler explicitement la façon dont les transactions sont traitées dans le code de production.
la source
séparez chacune des pièces avec un BEGIN TRAN et vérifiez si la transaction a réussi. s'il a été validé, sinon faites une restauration, car ils s'exécutent tous à partir du même niveau, vous pourrez valider chaque section séparément sans avoir à tout restaurer en cas d'échec.
Pour plus d'informations, vous pouvez consulter: http://msdn.microsoft.com/en-us/library/ms188929.aspx
la source