Sql server 提交后是否回滚事务?

Sql server 提交后是否回滚事务?,sql-server,tsql,transactions,commit,rollback,Sql Server,Tsql,Transactions,Commit,Rollback,我遇到了一些问题,看起来很像存储过程中的事务已回滚,尽管我相当肯定它已提交,因为直到提交之后才设置输出变量,并且用户获得了我知道的输出变量的值,因为他们会打印出来,我还设置了一个日志表,在其中输入输出变量的值。 理论上,有人可以手动删除和更新数据,使其看起来像是回滚,但这是极不可能的 所以,我希望有人能在我的存储过程中发现某种结构错误。会见鲍勃: CREATE procedure [dbo].[BOB] (@output_id int OUTPUT, @output_msg varchar(25

我遇到了一些问题,看起来很像存储过程中的事务已回滚,尽管我相当肯定它已提交,因为直到提交之后才设置输出变量,并且用户获得了我知道的输出变量的值,因为他们会打印出来,我还设置了一个日志表,在其中输入输出变量的值。 理论上,有人可以手动删除和更新数据,使其看起来像是回滚,但这是极不可能的

所以,我希望有人能在我的存储过程中发现某种结构错误。会见鲍勃:

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\u id,这是SCOPE\u标识,他还得到一个@output\u msg,上面写着“ok”。他有没有办法在不提交事务的情况下获得这些输出


谢谢。

就我个人而言,我从未在存储过程中使用过事务,尤其是当许多人同时使用它们时。我也非常避免使用光标

我想我应该把temp_table的相关行传递到一个真正的temp table中,然后对所有行使用if语句。这在tsql中非常简单:

从“正常”表格中选择“温度”中的数据


检查每一行,执行作业,然后在最后一行不符合条件时回滚整个过程,这有什么意义?一次检查所有人,一次完成所有人的工作。这就是sql的全部内容。

您知道问题在于事务不支持变量回滚,因为数据库中没有数据更改。事务的提交或回滚只会对那些数据库对象表、临时表等产生影响,而不会对包括表变量在内的变量产生影响

-编辑

结果如下


我在你的程序中没有看到任何会导致你所说的行为发生的东西。然而,我认为使用这样的游标并不是做这类事情的最有效的方法。从多个角度来看,最好将其改为基于集合的方法,而不是RBAR。感谢您的回复。但我不相信在这种情况下真的有一种基于集合的方法可以奏效。无论如何,大多数情况下临时表包含的行不到五行,所以这应该没有多大关系。我至少建议使用实际的临时表,而不是像临时表一样使用持久表。当并发开始发挥作用时,这是有问题的。不幸的是,如果不重写一大块系统,这是不可能的:/n如果多个用户使用相同的用户凭据同时调用该过程,是否可能会在事务中发生奇怪的事情?我实际上已经更改了该过程这样它就可以将行传递给一个真正的临时表。这并没有解决我的问题。关于光标:如果我必须在没有光标的情况下进行操作,那么这将是非常复杂的代码。根据物品的类型,有很多检查各种奇怪的东西。我明白你的观点,先检查所有东西,但我认为这在这种情况下没有意义,我也不明白这与交易的问题有什么关系:我不明白你为什么要回避它。那么,您如何确保不会得到一半的交易?事实上,对这个系统来说,它要么发生,要么不发生是至关重要的。任何介于两者之间的事情都是不允许的。从一个抽象的例子中很难理解你到底需要什么。我不希望OLTP数据库在一个事务中需要如此多的更新。但是,如果您可以异步工作,那么有更好的方法。构建一个中间表,在中间表中输入事务数据,而不是更新所有这些表。添加状态列status。让一个进程定期解析此表并执行状态为null的事务。完成每个事务后,将状态更新为“完成”或“失败”。这样,您将创建一个事务队列。您的事务将一个接一个地发生,不需要嵌套事务;谢谢你指出这一点。我真的没有想到这一点。但是,直到提交之后才设置变量的值。另外,我在问题中没有提到的是,在将@output_id返回给用户之后,用户根据id从表中获取数据,这是成功的。但是,一段时间之后,数据仍然不存在。变量值的设置取决于查询,而不是事务提交或回滚。我添加了一些查询和结果来向您展示。希望有帮助是的,我明白你的意思。但在我的例子中,它更像这样:声明@v int;begin tran;-将行添加到表中;提交传输;设置@v=1;不管怎样,我真的很感谢你的回复,因为这很重要,我在之前没有考虑过
我现在知道了。然而,这并不能解决我的问题。但它可能仍然对我有帮助,所以我对你的答案投了更高的票:在这种情况下,我想@v是一个某种标志,用来显示插入是否完成。因为您无法回滚变量的值。您可以改为在表中设置一列。
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