提交后回滚事务?

时间:2016-02-01 13:18:52

标签: sql-server tsql transactions commit rollback

我遇到了一些看起来很像存储过程中的事务的问题已被回滚,即使我很确定它已被提交,因为输出变量直到提交后才设置,并且用户获取输出变量的值(我知道,因为它们将其打印出来并且我还设置了一个日志表,其中我输入了输出变量的值)。 从理论上讲,有人可以手动删除和更新数据,使其看起来像回滚,但这种可能性极小。

所以,我希望有人能在我的存储过程中发现某种结构性错误。认识BOB:

CREATE procedure [dbo].[BOB] (@output_id int OUTPUT, @output_msg varchar(255) OUTPUT)
as
BEGIN
SET NOCOUNT ON 
DECLARE @id int
DECLARE @record_id int

SET @output_id = 1

-- some preliminary if-statements that doesn't alter any data, but might do a RETURN

SET XACT_ABORT ON
BEGIN TRANSACTION

BEGIN TRY
    --insert into table A

    SET @id = SCOPE_IDENTITY()

    --update table B

    DECLARE csr cursor local FOR 
        SELECT [some stuff] and record_id
        FROM temp_table_that_is_not_actually_a_temporary_table
    open csr

    fetch next from csr into [some variables], @record_id
    while @@fetch_status=0
    begin   
        --check type of item + if valid
        IF (something)
        BEGIN
            SET SOME VARIABLE
        END
        ELSE
        BEGIN
            ROLLBACK TRANSACTION
            SET @output_msg = 'item does not exist'
            SET @output_id = 0
            RETURN
        END

        --update table C

        --update table D

        --insert into table E

        --execute some other stored procedure (without transactions)

        if (something)
        begin
            --insert into table F

            --update table C again      
        end

        DELETE FROM temp_table_that_is_not_actually_a_temporary_table WHERE record_id=@record_id

        fetch next from csr into [some variables], @record_id
    end
    close csr
    deallocate csr

    COMMIT TRANSACTION
    SET @output_msg = 'ok'
    SET @output_id = @id
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION
    SET @output_msg = 'transaction failed !'
    SET @output_id = 0
    INSERT INTO errors (record_time, sp_name, sp_msg, error_msg)
    VALUES (getdate(), 'BOB', @output_msg, error_message())
END CATCH

RETURN
END

我知道,我的用户获得了一个@output_id,即SCOPE_IDENTITY(),并且他还获得了一个'okput'的@output_msg。有没有什么方法可以在没有提交交易的情况下获得这些输出?

谢谢。

2 个答案:

答案 0 :(得分:1)

您知道问题是交易不支持对变量进行回滚,因为数据库内部没有数据更改。提交或回滚事务只会对这些数据库对象(表,临时表等)产生影响,而不是变量(包括表变量)。

- 的修改

declare @v1 int = 0, @v2 int = 0, @v3 int = 0

set @v2 = 1

begin tran
set @v1 = 1
commit tran

begin tran
set @v3 = 1
rollback tran

select @v1 as v1, @v2 as v2, @v3 as v3

结果如下

enter image description here

答案 1 :(得分:0)

就我个人而言,我从未在存储过程中使用过交易,特别是当它们被许多人同时使用时。我也很认真地避免使用游标。

我想我会将所涉及的temp_table_that_is_not_actually_a_temporary_table行传递到真正的临时表中,然后将所有行的if语句一起使用。这在tsql中非常简单:

从(normal_table)中选择(数据)到#temp,其中(条件)。

如果说最后一行不符合条件,检查每一行,完成工作然后回滚整个事情的重点是什么?立即检查所有这些,立即为所有人完成工作。这就是sql的全部内容。