使用 THROW througout usp 进行数据验证,回滚?
Use THROW througout usp for data validation, with rollback?
我有一个查询可以预先检查来自应用程序的数据,以确保应用程序没有传递错误数据。如果有一块坏数据,则使用 THROW 引发错误。这是否让我的交易保持开放状态,因为我当时没有碰到 catch 块?如果是这样,我将如何处理?
例如:
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 确实需要在事务中,所以将它放在事务之外不是一个选项。
我会以不同的方式处理这个问题,
在完成验证之前不要打开事务,如果验证失败,则会在 try 块中引发错误,控制将跳转到 catch 块 ignoring/skipping try 块中的其余代码。
我添加了检查 IF(@@TRANCOUNT <> 0) ROLLBACK TRAN,因为在验证期间可能会出现错误,在这种情况下,交易将永远不会打开。
只有在执行更新语句时出现问题时,控件才会跳转到 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
将 catch 块中的语句更改为:
if xact_state() = 1 rollback tran
-1 仅在非常特殊的情况下出现,我认为您不会在查询中遇到这种情况。如果您将其更改为在任何非 0 的 xact_state 上回滚,您应该停止挂起事务。
此外,我认为您不应该在 TRY 块中使用 THROW;只是捕获块。您想使用 raiserror() 在 try 块中触发错误,然后如果您愿意,在 catch 块中使用 throw。
我有一个查询可以预先检查来自应用程序的数据,以确保应用程序没有传递错误数据。如果有一块坏数据,则使用 THROW 引发错误。这是否让我的交易保持开放状态,因为我当时没有碰到 catch 块?如果是这样,我将如何处理?
例如:
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 确实需要在事务中,所以将它放在事务之外不是一个选项。
我会以不同的方式处理这个问题,
在完成验证之前不要打开事务,如果验证失败,则会在 try 块中引发错误,控制将跳转到 catch 块 ignoring/skipping try 块中的其余代码。
我添加了检查 IF(@@TRANCOUNT <> 0) ROLLBACK TRAN,因为在验证期间可能会出现错误,在这种情况下,交易将永远不会打开。
只有在执行更新语句时出现问题时,控件才会跳转到 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
将 catch 块中的语句更改为:
if xact_state() = 1 rollback tran
-1 仅在非常特殊的情况下出现,我认为您不会在查询中遇到这种情况。如果您将其更改为在任何非 0 的 xact_state 上回滚,您应该停止挂起事务。
此外,我认为您不应该在 TRY 块中使用 THROW;只是捕获块。您想使用 raiserror() 在 try 块中触发错误,然后如果您愿意,在 catch 块中使用 throw。