SQL Server 작업의 트랜잭션 및 시도 잡기


9

SQL Server 작업의 각 단계마다 DML 작업이 있습니다. 업데이트를 확인하려면 / 삽입이 뭔가 잘못 경우 롤백 될 것이다, 나는의 데이터 수정 감쌌다 각 단계TRY CATCHTRANSACTION블록 :

BEGIN TRY
    BEGIN TRANSACTION

        [[INSERT/update statements]] ...

    IF @@TRANCOUNT > 0
    BEGIN
        COMMIT TRANSACTION
        PRINT 'Successful.'
    END

END TRY

BEGIN CATCH
    SELECT
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage

    IF @@TRANCOUNT > 0
    BEGIN
        ROLLBACK TRANSACTION
        PRINT 'Unsuccessful.'
    END
END CATCH

오류 발생시 데이터 조작이 롤백되도록 보장합니까? 또는 다른 고려 사항을 고려해야합니까?

구성 등을 사용하여 더 나은 방법이 있습니까?

감사합니다.

답변:


7

오히려 예외 처리 및 중첩 트랜잭션과 같은 패턴을 권장합니다 .

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch   
end

이 패턴 XACT_STATE()은 catch 블록을 검사하여 커밋 할 수없는 트랜잭션 을 방지 합니다 .

커밋 할 수없는 트랜잭션 및 XACT_STATE
TRY 블록에서 생성 된 오류로 인해 현재 트랜잭션의 상태가 무효화되면 트랜잭션은 커밋 할 수없는 트랜잭션으로 분류됩니다. 일반적으로 TRY 블록 외부에서 트랜잭션을 종료하는 오류는 TRY 블록 내부에서 오류가 발생할 때 트랜잭션을 커밋 할 수없는 상태로 만듭니다. 커밋 할 수없는 트랜잭션은 읽기 작업 또는 ROLLBACK TRANSACTION 만 수행 할 수 있습니다. 트랜잭션은 쓰기 작업 또는 COMMIT TRANSACTION을 생성하는 Transact-SQL 문을 실행할 수 없습니다. 트랜잭션이 커밋 할 수없는 트랜잭션으로 분류 된 경우 XACT_STATE 함수는 값 -1을 반환합니다. 일괄 처리가 완료되면 데이터베이스 엔진은 커밋 할 수없는 모든 활성 트랜잭션을 롤백합니다. 트랜잭션이 커밋 할 수없는 상태가되었을 때 오류 메시지가 전송되지 않은 경우, 일괄 처리가 완료되면 오류 메시지가 클라이언트 응용 프로그램으로 전송됩니다. 커밋 할 수없는 트랜잭션이 감지되어 롤백되었음을 나타냅니다.

귀하의 코드는 @@TRANCOUNT0이 될 수없는 곳을 확인하고 있으며, 정보 제공 PRINT 메시지와 성공을 알리기 위해 SELECT 결과 세트가 혼합되어 있으며 복구 가능한 오류를 처리하지 않습니다. 이상적으로 클라이언트,이 경우에는 에이전트 작업 (예 : 캐치가 다시 발생해야 함)으로 예외가 전파되어야합니다.


유용한 답변과 환상적인 웹 사이트에 감사드립니다! 그러나 여전히이 패턴을 간단한 DML 문 (저장 프로 시저가 아닌)과 함께 사용할 수 있는지 궁금합니다. 또한 아래와 같이 거래를 저장해야합니까? (사용할 상점 절차가 없습니다) : save transaction usp_my_procedure_name;
Sky

2

당신이 나에게 좋아 보인다. 트랜잭션을 롤백 한 후 물론 정보를 사용하여 로그에 기록하는 것이 좋습니다.


1
답장을 보내 주셔서 감사합니다. 로그에 쓰는 방법에 대한 힌트를 제공해 주시겠습니까?
Sky

3
오류 또는 데이터를 로그 테이블에 쓰려면 롤백을 수행하기 전에 원하는 데이터를 테이블 변수에 복사하십시오 (테이블 변수를 사용하는 것이 중요합니다. 임시 테이블이 롤백됩니다). 롤백 한 다음 테이블 변수의 데이터를 로깅 테이블에 삽입하십시오.
HLGEM
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.