标题真的是这个问题:在T#中是否存在与C#相同的“抛出”;重新抛出异常?
在C#中,可以这样做:
try
{
DoSomethingThatMightThrowAnException();
}
catch (Exception ex)
{
// Do something with the exception
throw; // Re-throw it as-is.
}
T-SQL的BEGIN CATCH
功能中是否有相同的功能?
答案 0 :(得分:33)
您可以使用RAISERROR。来自RAISERROR上的MSDN documentation:
BEGIN TRY
-- RAISERROR with severity 11-19 will cause execution to
-- jump to the CATCH block
RAISERROR ('Error raised in TRY block.', -- Message text.
16, -- Severity.
1 -- State.
);
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT @ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
-- Use RAISERROR inside the CATCH block to return
-- error information about the original error that
-- caused execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
END CATCH;
编辑:
这与c#的throw
或throw ex
完全不同。正如@henrikstaunpoulsen指出你没有在新错误中得到原始错误号(RAISERROR受限于它可以使用的数字)。您必须使用某种约定并从消息中解析信息(如果可用)。
MSDN有一篇文章Using TRY...CATCH in Transact-SQL,我使用了一些代码来创建下面的测试:
use test;
GO
IF OBJECT_ID (N'usp_RethrowError',N'P') IS NOT NULL
DROP PROCEDURE usp_RethrowError;
GO
CREATE PROCEDURE usp_RethrowError AS
IF ERROR_NUMBER() IS NULL
RETURN;
DECLARE
@ErrorMessage NVARCHAR(4000),
@ErrorNumber INT,
@ErrorSeverity INT,
@ErrorState INT,
@ErrorLine INT,
@ErrorProcedure NVARCHAR(200);
SELECT
@ErrorNumber = ERROR_NUMBER(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorLine = ERROR_LINE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage =
N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' +
'Message: '+ ERROR_MESSAGE();
RAISERROR
(
@ErrorMessage,
@ErrorSeverity,
@ErrorState,
@ErrorNumber, -- parameter: original error number.
@ErrorSeverity, -- parameter: original error severity.
@ErrorState, -- parameter: original error state.
@ErrorProcedure, -- parameter: original error procedure name.
@ErrorLine -- parameter: original error line number.
);
GO
PRINT 'No Catch'
DROP TABLE XXXX
PRINT 'Single Catch'
BEGIN TRY
DROP TABLE XXXX
END TRY
BEGIN CATCH
EXEC usp_RethrowError;
END CATCH;
PRINT 'Double Catch'
BEGIN TRY
BEGIN TRY
DROP TABLE XXXX
END TRY
BEGIN CATCH
EXEC usp_RethrowError;
END CATCH;
END TRY
BEGIN CATCH
EXEC usp_RethrowError;
END CATCH;
产生以下输出:
No Catch
Msg 3701, Level 11, State 5, Line 3
Cannot drop the table 'XXXX', because it does not exist or you do not have permission.
Single Catch
Msg 50000, Level 11, State 5, Procedure usp_RethrowError, Line 25
Error 3701, Level 11, State 5, Procedure -, Line 7, Message: Cannot drop the table 'XXXX', because it does not exist or you do not have permission.
Double Catch
Msg 50000, Level 11, State 5, Procedure usp_RethrowError, Line 25
Error 50000, Level 11, State 5, Procedure usp_RethrowError, Line 25, Message: Error 3701, Level 11, State 5, Procedure -, Line 16, Message: Cannot drop the table 'XXXX', because it does not exist or you do not have permission.
答案 1 :(得分:14)
在SQL 2012中,他们添加了新的THROW关键字,也可用于重新抛出异常
USE tempdb;
GO
CREATE TABLE dbo.TestRethrow
( ID INT PRIMARY KEY
);
BEGIN TRY
INSERT dbo.TestRethrow(ID) VALUES(1);
-- Force error 2627, Violation of PRIMARY KEY constraint to be raised.
INSERT dbo.TestRethrow(ID) VALUES(1);
END TRY
BEGIN CATCH
PRINT 'In catch block.';
THROW;
END CATCH;
答案 2 :(得分:2)
以下是我回滚事务后用于重新抛出异常的内容。这也给出了错误的行号信息。
BEGIN TRY
BEGIN TRANSACTION -- Start the transaction
-- Do your work here
-- Commit the transaction
COMMIT TRANSACTION
END TRY
BEGIN CATCH
-- There was an error, rollback the transaction
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION
-- Raise an error with the details of the exception
DECLARE @ErrorMessage nvarchar(2048)
DECLARE @ErrorProcedure nvarchar(128)
DECLARE @ErrorState int
DECLARE @ErrorLine int
DECLARE @ErrorSeverity int
SET @ErrorProcedure = ERROR_PROCEDURE()
SET @ErrorLine = ERROR_LINE()
SET @ErrorSeverity = ERROR_SEVERITY()
SET @ErrorState = ERROR_STATE()
SET @ErrorMessage = ''
IF @ErrorProcedure IS NOT NULL
SET @ErrorMessage = @ErrorMessage + @ErrorProcedure + ' ';
IF @ErrorLine IS NOT NULL
SET @ErrorMessage = @ErrorMessage + '[Line ' + CAST(@ErrorLine as nvarchar) + '] ';
SET @ErrorMessage = @ErrorMessage + ERROR_MESSAGE()
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH
答案 3 :(得分:2)
为了防止在多个捕获场景中重复过程信息/错误/行号,我使用了类似的过程,稍作修改如下:
IF @Error_Procedure <> OBJECT_NAME(@@PROCID)
BEGIN
RAISERROR('[Procedure: %s]: Nest Level: %d; Line: %d; Error Number: %d; Message: %s',@Error_Severity,@Error_State,@Error_Procedure, @NestLevel, @Error_Line, @Error_Number, @Error_Message)
END
ELSE
BEGIN
RAISERROR(@Error_Message,@Error_Severity,@Error_State)
END
因此,如果我们已经使用此SP捕获并重新引发错误,我们不会重复添加其他信息,因此在外部范围内,我们只会看到最初重新引发的错误。
在上面发布的示例中,双捕获输出与单捕获输出相同。我还在错误消息中包含嵌套级别以帮助调试。
答案 4 :(得分:0)
您可以使用RAISEERROR
引发异常答案 5 :(得分:0)
我通常使用以下内容:
DECLARE @Outcome as bit
DECLARE @Error as int
BEGIN TRANSACTION
-- *** YOUR TSQL TRY CODE HERE ****
-- Capture the TSQL outcome.
SET @Error = @@ERROR
-- Set the Outcome to be returned to the .NET code to successful
SET @Outcome = 1
IF @Error <> 0
BEGIN
-- An Error was generate so we invoke ROLLBACK
ROLLBACK
-- We set the Outcome to be returned to .Net to unsuccessful
SET @Outcome = 0
end
ELSE
BEGIN
-- The transaction was successful, invoke COMMIT
COMMIT
END
-- Returning a boolean value to the .NET code
Select @Outcome as Outcome