28

SQLServer2008に次のSQLステートメントがあるとします。

BEGIN TRANSACTION    
SqlStatement1    
EXEC sp1    
SqlStatement3
COMMIT TRANSACTION

sp1のコード

BEGIN TRANSACTION
SqlStatement2
ROLLBACK TRANSACTION

私の質問は:SqlStatement3実際に実行されますか?

4

5 に答える 5

34

SQL Serverは、ネストされたトランザクションを実際にはサポートしていません。一度に1つのトランザクションのみがあります。

この1つのトランザクションには、基本的なネストされたトランザクションカウンターがあり@@TRANCOUNTます。連続するたびbegin transactionに、カウンターが1ずつ増加し、それぞれが1ずつcommit transaction減少します。カウンターを0に減らすものだけが、commit実際に1つのトランザクションをコミットします。

Arollback transactionは、1つのトランザクションを元に戻し、クリアします@@TRANCOUNT

あなたの場合、面白い結果はSqlStatement3がトランザクションので実行されるということです!ファイナルcommitは「COMMITTRANSACTIONリクエストには対応するBEGINTRANSACTIONがありません」という例外をスローしますが、SqlStatement3の効果は永続的です。

例えば:

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

プリントし4ます。本当に。:)

于 2012-09-17T09:50:57.563 に答える
18

トランザクションセーブポイントを使用できます。sp1は、エラー処理とネストされたトランザクションで説明されているようなパターンを使用できます。

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

このようなパターンにより、sp1で実行された作業をロールバックできますが、包含トランザクションはアクティブのままになります。

于 2012-09-17T11:56:43.463 に答える
5

Rollback transaction単独ですべてのトランザクションをロールバックします。

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

ステートメントは引き続き実行されます-これを試してください

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
于 2012-09-17T09:37:43.123 に答える
5

ネストされたトランザクションを使用できます。内部トランザクションのみをロールバックするには、セーブポイントを使用してセーブポイントにロールバックします。内部トランザクションがネストされているかどうかに関係なく、IFステートメントを使用して、セーブポイントを設定するかどうか、およびセーブポイントにロールバックするかロールバックするかを確認できます。

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
于 2017-02-08T08:39:24.793 に答える
4

内部トランザクションのコミットは、SQLServerデータベースエンジンによって無視されます。トランザクションは、最も外側のトランザクションの最後に実行されたアクションに基づいて、コミットまたはロールバックされます。外部トランザクションがコミットされると、内部のネストされたトランザクションもコミットされます。外部トランザクションがロールバックされると、内部トランザクションが個別にコミットされたかどうかに関係なく、すべての内部トランザクションもロールバックされます。

MicrosoftTechNetでのネストトランザクション

于 2016-11-09T12:06:55.913 に答える