回滚嵌套事务的内部事务

Niy*_*wan 20 sql-server transactions

假设我在sql server 2008中有以下sql语句:

BEGIN TRANSACTION    
SqlStatement1    
EXEC sp1    
SqlStatement3
COMMIT TRANSACTION
Run Code Online (Sandbox Code Playgroud)

sp1的代码

BEGIN TRANSACTION
SqlStatement2
ROLLBACK TRANSACTION
Run Code Online (Sandbox Code Playgroud)

我的问题是:SqlStatement3实际执行了吗?

And*_*mar 26

SQL Server并不真正支持嵌套事务.一次只有一个交易.

这一个事务有一个基本的嵌套事务计数器@@TRANCOUNT.每个连续begin transaction计数器将计数器递增1,每个计数器commit transaction将其减1.只有将commit计数器减少到0才真正提交一个事务.

A rollback transaction撤消一个事务并清除@@TRANCOUNT.

在您的情况下,有趣的结果是SqlStatement3 事务运行!你的final commit将抛出"COMMIT TRANSACTION请求没有相应的BEGIN TRANSACTION"异常,但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
Run Code Online (Sandbox Code Playgroud)

打印4.真.:)

  • 这个答案的想法是正确的,但是这个例子并不能证明任何事情,因为表变量不受回滚的影响。如果删除最后一个 UPDATE 语句,则该行的最终值将为 3,而不是 1。将表变量更改为临时表将使该示例有效。 (2认同)

Rem*_*anu 13

您可以使用事务保存点.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
Run Code Online (Sandbox Code Playgroud)

这样的模式允许在sp1中完成的工作回滚,但保持包含事务处于活动状态.


use*_*048 6

SQL Server 数据库引擎会忽略提交内部事务。根据最外层事务结束时采取的操作来提交或回滚事务。如果提交了外部事务,则内部嵌套事务也会提交。如果回滚外部事务,则所有内部事务也会回滚,无论内部事务是否单独提交。

Microsoft TechNet 中的嵌套事务


pod*_*ska 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
Run Code Online (Sandbox Code Playgroud)


JvS*_*JvS 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
Run Code Online (Sandbox Code Playgroud)