使用THROW通过usp进行数据验证,还是回滚?

时间:2015-01-12 22:19:06

标签: sql sql-server

我有一个查询,它会预先检查来自应用程序的数据,以确保应用程序没有传递错误的数据。如果有一个坏数据,则使用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确实需要在事务中,因此将它放在事务之外不是一种选择。

2 个答案:

答案 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。