SQL Server에서 동일한 예외를 다시 발생시키는 방법
내 try 블록에서 발생한 SQL 서버에서 동일한 예외를 다시 발생시키고 싶습니다. 같은 메시지를 던질 수 있지만 같은 오류를 던지고 싶습니다.
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 오류가 발생하지만 전달중인 오류 번호를 던지고 싶습니다 @@error.
이 오류를 프런트 엔드에서 캡처하고 싶습니다.
즉
catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}
이 기능을 원합니다. raiseerror로는 달성 할 수 없습니다. 백엔드에서 사용자 지정 오류 메시지를주고 싶지 않습니다.
RAISEERROR는 catch에서 throw되는 ErrorNo를 전달할 때 아래 언급 된 오류를 반환해야합니다.
Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,14 행 UNIQUE KEY 제약 조건 'UK_DomainCode'위반. 'Tags.tblDomain'개체에 중복 키를 삽입 할 수 없습니다. 그 진술서는 만료되었습니다.
편집하다:
저장 프로 시저에 실행해야하는 여러 쿼리가 포함되어 있다는 점을 고려하여 프런트 엔드에서 예외를 처리하려는 경우 try catch 블록을 사용하지 않는 단점은 무엇일까요?
다음은 오류가 발생하는 경우 일련의 문을 롤백하고 오류 메시지를보고하는 완전한 기능의 정리 코드 샘플입니다.
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();
rollback transaction;
raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
SQL 2012에는 throw 문이 도입되었습니다.
http://msdn.microsoft.com/en-us/library/ee677615.aspx
THROW 문이 매개 변수없이 지정되면 CATCH 블록 안에 나타나야합니다. 이로 인해 포착 된 예외가 발생합니다.
BEGIN TRY
BEGIN TRANSACTION
...
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
THROW
END CATCH
CATCH 블록 내에서 다시 던지기 (SQL2012 이전 코드, SQL2012 이상에는 THROW 문 사용) :
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 명령 또는 특정 오류 만 포착하는 기능을 도입 할 것입니다. 그러나 지금은 해결 방법을 사용하십시오. 죄송합니다.
당신은 할 수 없습니다 : 오직 엔진 만이 50000 미만의 오류를 던질 수 있습니다. 당신이 할 수있는 일은 다음 과 같은 예외를 던지는 것뿐입니다 .
여기 질문자는 클라이언트 측 트랜잭션을 사용하여 그가 원하는 것을 수행했습니다.
좋아, 이것은 해결 방법입니다 ... :-)
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 블록을 확인하면 오류가 발생하지 않고 실제 오류 번호를 반환합니다 (또한 트랜잭션을 롤백합니다). 이제 .NET 코드에서 예외를 포착하는 대신 ExecuteScalar ()를 사용하면 원하는 실제 오류 번호를 얻고 적절한 번호를 표시합니다.
int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
MessageBox.Show("Some message");
}
도움이 되었기를 바랍니다,
EDIT :- Just a note, If you want to get the number of records affected and trying to use ExecuteNonQuery, the above solution may not work for you. Otherwise, I think It would suit what you need. Let me know.
The way to stop execution in a stored procedure after an error has occurred and bubble the error back to the calling program is to follow each statement that might throw an error with this code:
If @@ERROR > 0
Return
I was surprised myself to find out that execution in a stored procedure can continue after an error - not realizing this can lead to some hard to track down bugs.
This type of error handling parallels (pre .Net) Visual Basic 6. Looking forward to the Throw command in SQL Server 2012.
Given that you haven't moved to 2012 yet, one way to implement the bubbling up of the original error code is to use the text message part of the exception you are (re)throwing from the catch block. Remember that it can contain some structure, for example, XML text for your caller code to parse in its catch block.
You can also create a wrapper stored procedure for the those scenarios when you want the SQL statement to be executed within the transaction and feed the error up to your code.
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'
From a design point of view, what is the point of throwing exceptions with original error numbers and custom messages? To some extent it breaks the interface contract between applications and the database. If you want to catch original errors and handle them in higher code, don't handle them in the database. Then when you catch an exception you can change the message presented to the user to anything you want. I would not do it though, because it makes your database code hmm 'not right'. As others said you should define a set of your own error codes (above 50000) and throw them instead. Then you can hanle integrity issues ('Duplicate values are not allowed') separately from potential business issues - 'Zip code is invalid', 'No rows were found matching the criteria' and so on.
참고URL : https://stackoverflow.com/questions/2481273/how-to-rethrow-same-exception-in-sql-server
'developer tip' 카테고리의 다른 글
| Lollipop의 backgroundTint는 버튼에 영향을주지 않습니다. (0) | 2020.10.11 |
|---|---|
| 이 응용 프로그램에는 / error에 대한 명시 적 매핑이 없습니다. (0) | 2020.10.11 |
| 런타임에 Android에서 텍스트의 일부를 굵게 만드는 방법은 무엇입니까? (0) | 2020.10.11 |
| Jest에서 모의 데이트를 어떻게 설정하나요? (0) | 2020.10.11 |
| 스핑크스 빌드 실패-autodoc이 모듈을 가져 오거나 찾을 수 없습니다. (0) | 2020.10.10 |