在T#中是否存在与C#相同的“抛出”;重新抛出异常?

时间:2009-11-04 13:57:36

标签: tsql exception-handling

标题真的是这个问题:在T#中是否存在与C#相同的“抛出”;重新抛出异常?

在C#中,可以这样做:

try
{
    DoSomethingThatMightThrowAnException();
}
catch (Exception ex)
{
    // Do something with the exception
    throw; // Re-throw it as-is.
}

T-SQL的BEGIN CATCH功能中是否有相同的功能?

6 个答案:

答案 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#的throwthrow 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;

http://msdn.microsoft.com/en-us/library/ee677615.aspx

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

引发异常

http://msdn.microsoft.com/en-us/library/ms178592.aspx

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