Question

J'ai une procédure stockée qui doit mettre un point de sauvegarde, de sorte qu'il peut, dans certaines circonstances, de défaire tout ce qu'il a fait et retourner un code d'erreur à l'appelant, ou accepter/commettre et retourne le succès de l'appelant.Mais j'en ai besoin pour travailler de savoir si l'appelant a déjà commencé une transaction ou pas.La doc est très confus sur ce sujet.Voici ce que je pense de fonctionner, mais je ne suis pas certain de toutes les ramifications.

La chose est - ce Stored Procedure (SP) est appelé par d'autres.Donc je ne sais pas si ils ont lancé une opération ou pas...Même si je obliger les utilisateurs à démarrer une transaction à utiliser mon SP, j'ai encore des questions sur la bonne utilisation de Save Points ...

Ma SP permettra de tester si une transaction est en cours, et si pas, créez-en une avec BEGIN TRANSACTION.Si une transaction est déjà en cours, qu'il va plutôt créer un point de sauvegarde avec SAVE TRANSACTION MySavePointName, et enregistrez le fait, c'est ce que j'ai fait.

Alors si j'ai à faire reculer mes modifications, si je fait un BEGIN TRANSACTION plus tôt, alors je vais ROLLBACK TRANSACTION.Si j'ai fait le point de sauvegarde, puis je vais ROLLBACK TRANSACTION MySavePointName.Ce scénario semble fonctionner à merveille.

C'est là que je suis un peu confus - si je veux continuer le travail que j'ai fait, si j'ai commencé une opération, je vais exécuter COMMIT TRANSACTION.Mais si j'ai créé un point de sauvegarde?J'ai essayé COMMIT TRANSACTION MySavePointName, mais ensuite, l'appelant tente de valider sa transaction et obtient une erreur:

La TRANSACTION de validation demande n'a pas de correspondant COMMENCER la TRANSACTION.

Alors je me demandais alors - un point de sauvegarde peut être restaurée (qui fonctionne: ROLLBACK TRANSACTION MySavePointName ne sera PAS revenir en arrière à l'appelant de la transaction).Mais peut-être que l'on n'a jamais besoin de "s'engager" il?Il reste simplement là, dans le cas où vous avez besoin de revenir à elle, mais disparaît une fois l'original de la transaction est validée (ou annulée)?

Si il ya une "meilleure façon" d'un "nid" d'une opération, veuillez jeter un peu de lumière.Je n'ai pas compris comment faire son nid avec BEGIN TRANSACTION mais seulement de restauration ou de commettre l'intérieur de ma transaction.Semble ROLLBACK va toujours revenir en haut de la transaction, tandis que COMMIT simplement décrémente @@trancount.

Était-ce utile?

La solution

Je crois que j'ai compris tout cela maintenant, alors je vais répondre à ma propre question...

J'ai même tenu un blog mes conclusions, si vous voulez plus de détails à http://geekswithblogs.net/bbiales/archive/2012/03/15/how-to-nest-transactions-nicely---quotbegin-transactionquot-vs-quotsave.aspx

Donc, mon SP commence avec quelque chose comme ça, pour démarrer une nouvelle transaction si il n'y a aucun, mais utiliser un Point de sauvegarde si l'on est déjà en cours:

DECLARE @startingTranCount int
SET @startingTranCount = @@TRANCOUNT

IF @startingTranCount > 0
    SAVE TRANSACTION mySavePointName
ELSE
    BEGIN TRANSACTION
-- …

Ensuite, lorsque vous êtes prêt à valider les modifications, vous avez seulement besoin d'engager si nous avons commencé l'opération de nous-mêmes:

IF @startingTranCount = 0
    COMMIT TRANSACTION

Et enfin, pour revenir simplement vos modifications jusqu'à présent:

-- Roll back changes...
IF @startingTranCount > 0
    ROLLBACK TRANSACTION MySavePointName
ELSE
    ROLLBACK TRANSACTION

Autres conseils

L'extension de Brian B de la réponse de.

Cela garantit le point de sauvegarde nom est unique et utilise le nouveau TRY/CATCH/JETER des fonctionnalités de SQL Server 2012.

DECLARE @mark CHAR(32) = replace(newid(), '-', '');
DECLARE @trans INT = @@TRANCOUNT;

IF @trans = 0
    BEGIN TRANSACTION @mark;
ELSE
    SAVE TRANSACTION @mark;

BEGIN TRY
    -- do work here

    IF @trans = 0
        COMMIT TRANSACTION @mark;
END TRY
BEGIN CATCH
    IF xact_state() = 1 OR (@trans = 0 AND xact_state() <> 0) ROLLBACK TRANSACTION @mark;
    THROW;
END CATCH

J'ai utilisé ce type de transaction manager dans mes Procédures Stockées :

    CREATE PROCEDURE Ardi_Sample_Test  
        @InputCandidateID INT  
    AS  
        DECLARE @TranCounter INT;  
        SET @TranCounter = @@TRANCOUNT;  
        IF @TranCounter > 0  
            SAVE TRANSACTION ProcedureSave;  
        ELSE  
            BEGIN TRANSACTION;  
        BEGIN TRY  

            /*
            <Your Code>
            */

            IF @TranCounter = 0  
                COMMIT TRANSACTION;  
        END TRY  
        BEGIN CATCH  
            IF @TranCounter = 0  
                ROLLBACK TRANSACTION;  
            ELSE  
                IF XACT_STATE() <> -1  
                    ROLLBACK TRANSACTION ProcedureSave;  

            DECLARE @ErrorMessage NVARCHAR(4000);  
            DECLARE @ErrorSeverity INT;  
            DECLARE @ErrorState INT;  
            SELECT @ErrorMessage = ERROR_MESSAGE();  
            SELECT @ErrorSeverity = ERROR_SEVERITY();  
            SELECT @ErrorState = ERROR_STATE();  

            RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);  
        END CATCH  
    GO  
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top