source

SQL Server에서 동일한 예외를 다시 던지는 방법

gigabyte 2023. 4. 24. 23:26
반응형

SQL Server에서 동일한 예외를 다시 던지는 방법

방금 시행 블록에서 발생한 것과 동일한 예외를 SQL Server에 다시 던지고 싶습니다.나는 같은 메시지를 보낼 수 있지만 같은 오류를 던지고 싶다.

BEGIN TRANSACTION
    BEGIN TRY
        INSERT INTO Tags.tblDomain (DomainName, SubDomainId, DomainCode, Description)
            VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
        COMMIT TRANSACTION
    END TRY
    
    BEGIN CATCH
        declare @severity int; 
        declare @state int;

        select @severity=error_severity(), @state=error_state();

        RAISERROR(@@Error,@ErrorSeverity,@state);
        ROLLBACK TRANSACTION
    END CATCH

RAISERROR(@@Error, @ErrorSeverity, @state);

이 행에는 에러가 표시되지만, 그런 기능을 원합니다.로 인해 50000이하지만, 에러 번호 50000을 .@@error ,

프런트 엔드에서 이 오류를 캡처하고 싶습니다.

예.

catch (SqlException ex)
{
    if ex.number==2627
    MessageBox.show("Duplicate value cannot be inserted");
}

이 기능을 원합니다.이 기능을 통해서는 달성할 수 없습니다.raiseerror백엔드에 커스텀에러 메시지를 표시하지 않습니다.

RAISEERROR에 ErrorNo를 됩니다.

Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,

14행 UNIQE KEY 제약 조건 'UK_DomainCode' 위반.개체 'Tags.tblDomain'에 중복 키를 삽입할 수 없습니다.문이 종료되었습니다.

편집:

stored procedure에 실행이 필요한 쿼리가 여러 개 포함되어 있는데 프런트 엔드에서 예외를 처리하려면 try catch block을 사용하지 않는 단점은 무엇입니까?

SQL 2012에서는 throw 스테이트먼트가 도입되었습니다.

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

매개 변수 없이 DLOW 문이 지정된 경우 CATCH 블록 안에 표시되어야 합니다.이것에 의해, 검출된 예외가 발생합니다.

BEGIN TRY
    BEGIN TRANSACTION
    ...
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW
END CATCH

다음으로 에러가 발생하여 오류 메시지가 보고되었을 때 일련의 문을 롤백하기 위한 완전한 기능의 클린 코드샘플을 나타냅니다.

begin try
    begin transaction;

    ...

    commit transaction;
end try
begin catch
    if @@trancount > 0 rollback transaction;
    throw;
end catch

SQL 2012 이전

begin try
    begin transaction;
    
    ...
    
    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    if @@trancount > 0 rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch

CATCH 블록 내부로 재투입(SQL2012 이전 코드, SQL2012 이상에서는 Drow 문 사용):

DECLARE
    @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(),
    @ErrorNumber int = ERROR_NUMBER(),
    @ErrorSeverity int = ERROR_SEVERITY(),
    @ErrorState int = ERROR_STATE(),
    @ErrorLine int = ERROR_LINE(),
    @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage;
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)

선택사항은 다음과 같습니다.

  • 오류를 발견하지 않음(거품이 일게 함)
  • 커스텀 키우기

SQL은 어떤 시점에서 reraise 명령 또는 특정 오류만 탐지하는 기능을 도입할 수 있습니다.하지만 지금은 회피책을 사용하세요.미안하다.

할 수 없습니다. 엔진만이 5만 미만의 오차를 발생시킬 수 있습니다.네가 할 수 있는 건 그렇게 보이는 예외를 두는 것뿐이야

여기서 제 답을 보세요.

질문자가 고객 측 거래를 이용해 원하는 일을 한 건 좀 바보같아요

좋아, 이건 회피책이야...:-)

DECLARE @Error_Number INT
BEGIN TRANSACTION 
    BEGIN TRY
    INSERT INTO Test(Id, Name) VALUES (newID(),'Ashish') 
    /* Column 'Name' has unique constraint on it*/
    END TRY
    BEGIN CATCH

            SELECT ERROR_NUMBER()
            --RAISERROR (@ErrorMessage,@Severity,@State)
            ROLLBACK TRAN
    END CATCH

catch block에 주목하면 에러가 발생하지 않고 실제 에러 번호가 반환됩니다(트랜잭션이 롤백됩니다).이제 에 들어갑니다.예외를 검출하는 대신 ExecuteScalar()를 사용하면 원하는 실제 에러 번호를 취득하고 적절한 번호를 표시합니다.

int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
    MessageBox.Show("Some message");
}

이게 도움이 됐으면 좋겠는데

편집 :- 주의사항입니다.해당 레코드의 수를 취득하여 ExecuteNonQuery를 사용하려고 하면 위의 솔루션이 작동하지 않을 수 있습니다.그렇지 않으면, 당신이 필요로 하는 것에 어울릴 것 같아요.알려줘.

오류가 발생한 후 저장 프로시저 실행을 중지하고 호출 프로그램으로 오류를 버블링하려면 다음 코드를 사용하여 오류를 발생시킬 수 있는 각 문을 따릅니다.

If @@ERROR > 0
Return

저장 프로시저에서의 실행이 오류 발생 후에도 계속된다는 것을 알고 놀랐습니다.이것을 깨닫지 못하면 버그를 추적하기 어려워질 수 있습니다.

이런 유형의 오류 처리는 병렬입니다(이전).넷) Visual Basic 6.SQL Server 2012에서 Throw 명령어를 기대하고 있습니다.

아직 2012년으로 이행하지 않았기 때문에 원래 에러 코드의 버블업을 구현하는 방법 중 하나는 캐치 블록에서 (다시) 던지고 있는 예외의 텍스트 메시지 부분을 사용하는 것입니다.발신자 코드의 캐치 블록에 해석하기 위한 XML 텍스트 등, 몇개의 구조를 포함할 수 있습니다.

트랜잭션 내에서 SQL 문을 실행하고 오류를 코드에 입력할 때 이러한 시나리오에 대한 래퍼 저장 프로시저를 생성할 수도 있습니다.

CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
    @SQL nvarchar(max)
)
AS

SET NOCOUNT ON

BEGIN TRY
    BEGIN TRANSACTION
        EXEC(@SQL)
    COMMIT TRANSACTION
END TRY

BEGIN CATCH
    DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
    SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
    ROLLBACK TRANSACTION
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH

GO

-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'

설계상의 관점에서, 원래의 에러 번호와 커스텀 메세지에 예외를 두는 목적은 무엇입니까?어느 정도 애플리케이션과 데이터베이스 간의 인터페이스 계약이 깨집니다.원래 오류를 찾아 더 높은 코드로 처리하려면 데이터베이스에서 처리하지 마십시오.그런 다음 예외를 발견하면 사용자에게 표시되는 메시지를 원하는 메시지로 변경할 수 있습니다.하지만 나는 그것을 하지 않을 것이다. 왜냐하면 그것은 너의 데이터베이스 코드를 흐음 '잘못'하게 만들기 때문이다.다른 사람이 말한 것처럼, 독자적인 에러 코드 세트(50000 이상)를 정의하고, 대신에 에러 코드를 폐기할 필요가 있습니다.그런 다음 무결성 문제('복제된 값은 허용되지 않습니다')를 잠재적인 비즈니스 문제(ZIP 코드가 잘못되었습니다), '기준과 일치하는 행을 찾을 수 없습니다' 등)와 별도로 지정할 수 있습니다.

언급URL : https://stackoverflow.com/questions/2481273/how-to-rethrow-the-same-exception-in-sql-server

반응형