SQL 2005 저장 프로 시저에서 오류 처리를 추가하는 가장 좋은 방법은 무엇입니까?


11

저장된 proc가 확장 성이 뛰어나고 오류 처리 기능을 포함 할 수있을 정도로 견고하게 만드는 좋은 방법은 무엇입니까?

또한 저장된 프로세스에서 여러 오류 시나리오를 처리하고 호출 앱에 의미있는 오류 정보를 반환하는 지능형 피드백 시스템을 갖추는 가장 좋은 방법은 무엇입니까?


2
SQL Server 2005에서 최신 TRY CATCH 블록을 사용해보십시오. sommarskog.se/error_handling_2005.html
Sankar Reddy

안녕하세요 @Kacalapy ~ 장래에 각 질문에 고유 한 질문을하도록 권장하고 있습니다. 이렇게하면 한 번에 하나의 질문에만 집중할 수 있습니다. 나는 당신 이이 질문으로 그렇게하는 것이 좋습니다.
jcolebrand

답변:


12

Alex Kuznetsov는 T-SQL TRY ... CATCH, T-SQL 트랜잭션 및 SET XACT_ABORT 설정 및 클라이언트 측 오류 처리 사용을 다루는 책인 방어 데이터베이스 프로그래밍 (8 장)에서 훌륭한 장을 가지고 있습니다. 달성해야 할 옵션에 가장 적합한 옵션을 결정하는 데 많은 도움이됩니다.

이 사이트 에서 무료 로 이용할 수 있습니다 . 나는 결코 회사와 제휴하지 않지만 그 책의 하드 카피 버전을 소유하고 있습니다.

이 주제에 대해서는 Alex가 잘 설명하는 많은 세부 사항이 있습니다.

닉의 요청에 따라 ... (이것이 모두 챕터에있는 것은 아닙니다)

스케일링 측면에서 DB 코드에 어떤 활동이 있어야하고 앱에 어떤 활동이 있어야하는지에 대해 정직해야합니다. 빠른 실행 코드가 방법 당 단일 관심사를 위해 설계로 돌아 오는 경향을 알고 계십니까?

가장 쉬운 통신 방법은 사용자 지정 오류 코드 (> 50,000)입니다. 꽤 빠릅니다. DB 코드와 앱 코드를 동기화 상태로 유지해야한다는 의미입니다. 사용자 정의 오류 코드를 사용하면 오류 메시지 문자열에 유용한 정보를 반환 할 수도 있습니다. 해당 상황에 맞는 오류 코드가 있으므로 오류 데이터 형식에 맞게 앱 코드로 파서를 작성할 수 있습니다.

또한 데이터베이스에서 논리를 다시 시도해야하는 오류 조건은 무엇입니까? X 초 후에 다시 시도하려면 앱 코드에서 처리하는 것이 좋습니다. 그래서 트랜잭션이 많이 차단되지 않습니다. DML 작업 만 즉시 다시 제출하면 SP에서 DML 작업을 반복하는 것이 더 효율적일 수 있습니다. 그러나 재 시도를 수행하려면 코드를 복제하거나 SP 계층을 추가해야 할 수 있습니다.

실제로, 그것은 현재 SQL Server의 TRY ... CATCH 논리에 가장 큰 고통입니다. 할 수는 있지만 약간의 귀찮습니다. SQL Server 2012에서 특히 개선 된 시스템 예외 (원래 오류 번호 유지)를 개선하는 방법을 찾아보십시오. 또한 FORMATMESSAGE있는데 , 이는 특히 로깅 목적으로 오류 메시지를 구성하는 데 약간의 유연성을 추가합니다.


훌륭한 조언과 아주 좋은 책!
Marian

Red Gate는 매우 유용한 무료 전자 책 몇 권을 제공하며이 책은 확실히 더 좋은 책 중 하나입니다. 좋은 제안.
Matt M

그들의 모든 책이 이것을하는 것은 아니지만, Kuznetsov의 "방어 적 ..."책의 무료 버전은 동시성에서 살아남는 트랜잭션 격리 레벨과 수정 개발에 관한 마지막 2 개의 장을 포함하지 않습니다. 나를 위해. 그 안에 들어있는 내용은 구매할 가치가있었습니다.
Phil Helmer

7

이 템플릿입니다 (오류 로깅 제거)

노트:

  • XACT_ABORT가 없으면 모든 TXN 시작 및 커밋 / 롤백이 쌍을 이루어야합니다.
  • 커밋이 @@ TRANCOUNT 감소
  • 롤백은 @@ TRANCOUNT를 0으로 반환하므로 오류 266이 발생합니다.
  • 현재 레이어 만 롤백 할 수 없습니다 (예 : 롤백시 @@ TRANCOUNT 감소)
  • XACT_ABORT는 오류 266을 억제합니다.
  • 저장된 각 프로시 저는 동일한 템플릿을 따라야하므로 각 호출은 원자 적입니다.
  • 롤백 검사는 실제로 XACT_ABORT로 인해 중복됩니다. 그러나 그것은 기분이 좋아지고, 이상하게 보이며, 원하지 않는 상황을 허용합니다.
  • 이는 클라이언트 측 TXN (LINQ와 같은)을 허용합니다.
  • Remus Rusanu 에는 저장 점을 사용 하는 유사한 쉘 이 있습니다. 원자 DB 호출을 선호하며 기사와 같은 부분 업데이트를 사용하지 않습니다.

... 필요한 것보다 더 많은 TXN을 만들지 마십시오

하나,

CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO

@@ TRANCOUNT가 0보다 크면 어떻게합니까? 당신은 어떤 일을하지 않거나 의견이 있습니까?
kacalapy

@kacalapy : 중첩 된 트랜잭션이 같은 것은 우리가 또 다른 시작되지 않도록 없다 scribd.com/doc/49579859/33/Nested-Transactions-Are-Real은
GBN

3

Try / Catch를 사용하지만 가능한 한 많은 정보를 수집하여 롤백 후 오류 로그에 기록합니다. 이 예에서 "LogEvent"는 발생한 이벤트의 세부 사항을 포함하는 EventLog 테이블에 쓰는 저장 프로 시저입니다. GetErrorInfo ()는 정확한 오류 메시지를 반환하는 함수 호출입니다.

오류가 발생하면 정보가 수집되고 프로시 저는 오류 처리 섹션으로 건너 뛰고 롤백을 발행합니다. 정보가 로그에 기록 된 다음 절차가 종료됩니다.

관련된 추가 프로 시저 / 함수 호출을 고려하면 약간 위에있는 것처럼 보입니다. 그러나이 방법은 문제를 디버깅 할 때 매우 유용합니다.

exec LogEvent @Process, @Database, 'blah blah blah를 삽입하려고합니다'
시작 시도
  MyTable에 삽입
  값을 선택하십시오
    MyOtherTable에서

  @rowcount = @@ ROWCOUNT를 선택하십시오.
시험 종료
-- 오류 처리
시작 캐치
  @error = ERROR_NUMBER ()를 선택하십시오.
         @rowcount = -1,
         @TableAction = '삽입',
         @TableName = @ 데이터베이스 + '.MyTable',
         @AdditionalInfo = '(blah blah blah 삽입 시도 중)'+ dbo.GetErrorInfo ()
   GOTO TableAccessError
엔드 캐치

.
.
.
.

TableAccessError :
IF (@@ TRANCOUNT> 0) 롤백
@output = upper (@TableAction) 선택 + 
       '오류-'+ 
       사례 (@TableAction)
         '업데이트'후 '업데이트'시
         '삭제'후 '삭제'
         else @TableAction + 'ing'
       끝 + 
       '레코드'+ 
       case (@TableAction) 
         '선택'후 '보낸 사람' 
         'update'다음 'in' 
         'insert'다음 'into'
         그렇지 않으면 '에서'   
         끝 + 
         ''+ @TableName + '테이블.'
@output = @output + '@@ ERROR 선택 :'+ convert (varchar (8), @ error) 
@output = @output + '@@ ROWCOUNT 선택 :'+ convert (varchar (8), @ rowcount) 

@output = @output + isnull (@AdditionalInfo, '')을 선택하십시오.
exec LogEvent @Process, @Database, @Output
로그가있는 RAISERROR (@ output, 16,1)
@ReturnCode = -1을 선택하십시오
GOTO THE_EXIT


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.