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é?
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.
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. :)
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
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.
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