Annulation de la transaction interne d'une transaction imbriquée

supposons que j'ai la déclaration sql suivante dans sql server 2008:

BEGIN TRANSACTION    
SqlStatement1    
EXEC sp1    
SqlStatement3
COMMIT TRANSACTION

le code de sp1

BEGIN TRANSACTION
SqlStatement2
ROLLBACK TRANSACTION

ma question Est: est SqlStatement3 réellement exécuté?

19
demandé sur Niyoko Yuliawan 2012-09-17 13:34:59

5 réponses

Vous pouvez utiliser transactions savepoints. sp1 pouvez utiliser un modèle comme celui décrit dans traitement des erreurs et Transactions imbriquées:

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch   
end

un tel schéma permet au travail effectué dans la sp1 de faire un retour en arrière, mais garde la transaction globale active.

12
répondu Remus Rusanu 2012-09-17 11:56:43

SQL Server ne supporte pas vraiment les transactions imbriquées. Il n'y a qu'une transaction à la fois.

ce mouvement a un compteur de mouvements de base imbriqué,@@TRANCOUNT. Chaque consécutifs begin transaction incrémente le compteur par un, chaque commit transaction réduit par un. Seul le commit qui réduit le compteur à 0 engage vraiment une seule transaction.

rollback transaction annule la transaction et efface @@TRANCOUNT.

dans votre cas, le résultat drôle est-ce que SqlStatement3 est exécuté dehors une transaction! Votre final commit lancera une exception "la requête de transaction de propagation n'a pas de TRANSACTION de début correspondante", mais les effets de SqlStatement3 sont permanents.

Par exemple:

create table #t (col1 int)
insert #t (col1) values (1)
BEGIN TRANSACTION
update #t set col1 = 2 -- This gets rolled back
BEGIN TRANSACTION
update #t set col1 = 3 -- This gets rolled back too
ROLLBACK TRANSACTION
update #t set col1 = 4 -- This is run OUTSIDE a transaction!
COMMIT TRANSACTION -- Throws error
select col1 from #t

Imprime 4. Vraiment. :)

25
répondu Andomar 2016-02-04 12:52:47

Rollback transaction sur son propre annule toutes les transactions.

http://msdn.microsoft.com/en-us/library/ms181299 (v=sql.100).aspx

la déclaration sera quand même exécutée - essayez ceci

create table #t (i int)
insert #t values (1)  -- t contains (1)

begin tran
    update #t set i = i +1
    select * from #t  -- t contains (2)
    begin tran
        update #t set i = i +1 
        select * from #t -- t contains (3)
    rollback tran  -- transaction is rolled back

select * from #t -- t contains (1)
update #t set i = i +1
select * from #t -- t contains (2)
commit    -- error occurs
select * from #t -- t contains (2)
drop table #t
4
répondu podiluska 2012-09-17 09:46:28

la propagation des transactions internes est ignorée par le moteur de base de données SQL Server. La transaction est engagée ou annulée sur la base des mesures prises à la fin de la transaction ultrapériphérique. Si la transaction externe est engagée, les transactions internes sont également engagées. Si la transaction externe est annulée, alors toutes les transactions internes sont également annulées, indépendamment du fait que les transactions internes aient été effectuées individuellement ou non. engager.

imbrication des Transactions dans Microsoft TechNet

3
répondu user2928048 2016-11-09 12:06:55

les transactions imbriquées peuvent être utilisées. Pour faire reculer la transaction interne, utilisez un point d'accès et un point d'accès. Si la transaction interne n'est pas imbriquée ou non, IF déclarations peuvent être utilisés pour savoir s'il faut définir un point de sauvegarde et décider de l'annulation ou de la restauration à un point de sauvegarde:

BEGIN TRAN

    DECLARE @WILL_BE_NESTED_TRANSACTION BIT = CASE WHEN (@@TRANCOUNT > 0) THEN 1 ELSE 0 END
    IF @WILL_BE_NESTED_TRANSACTION = 1
        SAVE TRAN tran_save
    BEGIN TRAN
        -- do stuff

    IF @WILL_BE_NESTED_TRANSACTION = 1
        ROLLBACK TRAN tran_save
    ELSE
        ROLLBACK

ROLLBACK
2
répondu JvS 2017-02-08 08:39:24