【问题标题】:Multiple Roll back for single Transcation单个事务的多次回滚
【发布时间】:2016-06-23 15:54:48
【问题描述】:

我必须更新表中的多个行。 我的要求是,如果由于某种原因,更新结果返回 0,那么应该回滚整个事务。 同时如果有异常发生,那么整个事务也必须回滚。

简而言之,如果更新语句返回 0 或更新表时发生任何异常,我需要回滚整个更新事务。

这是我使用的代码。

CREATE TYPE [DBO].[EMPLOYEETYPETABLETYPE] AS TABLE
( EmployeeStatusKey INT, EmployeeStatusName VARCHAR(50) )

CREATE PROCEDURE [dbo].[usp_UpdateEmployeeStatusType]

@EmploymentStatusDetails [DBO].[EMPLOYEETYPETABLETYPE] READONLY 

AS
 BEGIN

SET NOCOUNT ON;

DECLARE @TransactionName varchar(20) = 'UpdateEmployeeStatus';

DECLARE @rowcount1 INT

    BEGIN

    BEGIN TRY
        BEGIN TRANSACTION @TransactionName

            UPDATE  ES1
            SET
                ES1.EmployeeStatusName=ES2.EmployeeStatusName

            FROM 
                 [dbo].[EmployeeStatusTypes] ES1
            INNER JOIN 
                @EmploymentStatusDetails ES2
            ON 
                ES1.EmployeeStatusKey= ES2.EmployeeStatusKey

            SET
                @ROWCOUNT1=@@ROWCOUNT

            IF @rowcount1 =0
                GOTO PROBLEM

        PROBLEM:
        ROLLBACK TRAN  @TransactionName
    COMMIT
END TRY
    BEGIN CATCH
        SET @ROWCOUNT1=0
        ROLLBACK TRAN @TransactionName
    END CATCH

    IF @rowcount1 =0
        SELECT  -178,@rowcount1;
    ELSE
        SELECT  178,@rowcount1;
    END 


 END

我正在将数据表从 C# 代码传递给存储过程。 当我执行 Sp 时,没有抛出错误但是当我从 C# 代码中调用它时,我得到了异常

异常:ROLLBACK TRANSACTION 请求没有对应的 BEGIN TRANSACTION。

请提前帮助和感谢....

【问题讨论】:

  • 为什么要使用命名事务?
  • 我还建议你在多个地方打印@@trancount,看看你为什么会遇到这个问题。
  • @FLICKER 刚刚在教程中看到。

标签: sql-server commit rollback sqltransaction


【解决方案1】:

我用简化的脚本测试了你的脚本:

BEGIN TRY
    print 'A:' + cast(@@trancount as varchar)
    BEGIN TRANSACTION tranName

    print 'B:' + cast(@@trancount as varchar)
    GOTO PROBLEM -- you can comment this to simulate there is no error

    PROBLEM:
    begin
      ROLLBACK TRAN  tranName
      print 'there is a problem'
    end
    print 'C:' + cast(@@trancount as varchar)
    COMMIT
END TRY
BEGIN CATCH
    print 'D:' + cast(@@trancount as varchar)
    ROLLBACK TRAN tranName
END CATCH

当有问题时,输出是这样的

A:0
B:1
there is a problem
C:0
D:0
Msg 3903, Level 16, State 1, Line 18
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.

如果我评论GOTO PROBLEM所以没有问题,输出是这样的:

A:0
B:1
there is a problem
C:0
D:0
Msg 3903, Level 16, State 1, Line 18
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.

您会看到 GOTO 下的部分仍在执行中。

最后,COMMIT 仍然发生在没有可用事务的地方,所以COMMIT 抛出并出错。这意味着您的脚本会引发异常。

如果你摆脱 GOTO,你会很好。无论如何,使用GOTO 是一种不好的做法。

【讨论】:

    【解决方案2】:

    删除那个糟糕的 GOTO

    IF @rowcount1 =0
      ROLLBACK TRAN  @TransactionName
    ELSE
      COMMIT TRAN @TransactionName
    

    并查看 TRY-CATCH 文档。您必须通过检查 XACT_STATE() 值来检查是否有任何事务要提交或回滚。

    【讨论】:

    • 如果我去掉goto,那么如果update语句返回0怎么办(说主键=0时的条件)
    • 好吧,我为您提供了一些以if 开头的代码。现在,您的代码将在 ROLLBACK 之后立即在无条件 COMMIT 上失败。
    猜你喜欢
    • 1970-01-01
    • 2013-08-26
    • 2016-09-19
    • 1970-01-01
    • 2016-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多