单个事务的多次回滚
Posted
技术标签:
【中文标题】单个事务的多次回滚【英文标题】: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 刚刚在教程中看到。 【参考方案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 上失败。以上是关于单个事务的多次回滚的主要内容,如果未能解决你的问题,请参考以下文章