我有一个查询,它会预先检查来自应用程序的数据,以确保应用程序没有传递错误的数据。如果有一个坏数据,则使用THROW引发错误。这是否保持我的交易开放,因为我没有点击阻止块?如果是这样,我该如何处理?
例如:
BEGIN TRY
BEGIN TRANSACTION
IF NOT EXISTS(SELECT 1 FROM dbo.lutCode WHERE ID = @CodeID)
BEGIN
THROW('50001','Test Error',1)
END
UPDATE emp
SET emp.CodeID = @CodeID
WHERE emp.ID = @EmployeeID
IF XACT_STATE() = 1 COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() = -1 ROLLBACK TRANSACTION
THROW;
END CATCH
查询比这复杂得多,并且在实际查询中,IF EXISTS确实需要在事务中,因此将它放在事务之外不是一种选择。
答案 0 :(得分:2)
我会稍微改变一下,
在完成验证之前不要打开事务,如果验证失败,则在try块中引发错误,控件将跳转到catch块,忽略/跳过try块中的其余代码。
我添加了检查IF(@@ TRANCOUNT<> 0)ROLLBACK TRAN,因为在验证期间可能会引发错误,在这种情况下,永远不会打开事务。
只有在执行update语句时出现问题时,控件才会跳转到catch块而不提交事务,然后它将被回滚,其余的错误记录内容将被执行。
BEGIN TRY
-- do validatiion before openning transaction
IF NOT EXISTS(SELECT 1 FROM dbo.lutCode WHERE ID = @CodeID)
BEGIN
RAISERROR('Test Error',16, 1)
END
-- if test passed now open transaction
BEGIN TRANSACTION;
UPDATE emp
SET emp.CodeID = @CodeID
WHERE emp.ID = @EmployeeID
-- commit transaction if nothing gone wrong
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- Rollback transaction if something went wrong
-- after you opened the trasaction
IF (@@TRANCOUNT <> 0)
BEGIN
ROLLBACK TRANSACTION;
END
-- Other error logging
SELECT ERROR_LINE() AS Errorline
,ERROR_MESSAGE() AS ErrorMessage
,ERROR_NUMBER() AS ErrorNumber .......
END CATCH
答案 1 :(得分:1)
将catch块中的语句更改为:
if xact_state() = 1 rollback tran
-1只发生在非常特殊的情况下,我认为你不会在你的查询中。如果您将其更改为在任何非0的xact_state上回滚,则应该停止获取挂起的事务。
另外,我认为你不应该在TRY块中使用THROW;只是抓住了。你想使用raiserror()来触发try块中的错误,然后如果你选择,在catch块中使用throw。