[sql] EXECUTE 이후 트랜잭션 수는 BEGIN 및 COMMIT 문의 일치하지 않는 수를 나타냅니다. 이전 카운트 = 1, 현재 카운트 = 0

나는이 Insert데이터를 공급합니다 저장 프로 시저 Table1와 수 Column1의 값을 Table1과 표 2를 공급합니다 번째 저장 프로 시저를 호출합니다.

하지만 두 번째 저장 프로 시저를 다음과 같이 호출하면

Exec USPStoredProcName

다음과 같은 오류가 발생합니다.

EXECUTE 이후 트랜잭션 수는 BEGIN 및 COMMIT 문의 일치하지 않는 수를 나타냅니다. 이전 카운트 = 1, 현재 카운트 = 0.

나는 다른 질문에 대한 답변을 읽었으며 정확히 커밋 수가 엉망이되는 곳을 찾을 수 없습니다.



답변

TRY / CATCH 블록이있는 경우 가능한 원인은 트랜잭션 중단 예외를 포착하고 계속하는 것입니다. CATCH 블록에서는 항상 XACT_STATE()적절한 중단 및 커밋 할 수없는 (두꺼운) 트랜잭션을 확인 하고 처리 해야 합니다. 호출자가 트랜잭션을 시작하고 calee가 교착 상태 (트랜잭션을 중단 함)에 도달하면 호출 수신자가 트랜잭션이 중단되었으며 ‘평상시처럼 비즈니스’를 계속해서는 안된다는 것을 호출자에게 어떻게 전달할 것인가? 가능한 유일한 방법은 예외를 다시 발생시켜 호출자가 상황을 처리하도록하는 것입니다. 중단 된 트랜잭션을 조용히 삼키고 호출자가 계속해서 원래 트랜잭션에 있다고 가정하면 신체 상해 만이 보장 할 수 있습니다 (그리고 발생하는 오류는 엔진이 자체 보호를 시도하는 방식입니다).

중첩 트랜잭션 및 예외와 함께 사용할 수있는 패턴을 보여주는 예외 처리 및 중첩 트랜잭션살펴볼 것을 권장합니다 .

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
go


답변

나도이 문제가 있었다. 저에게 이유는 제가하고 있었기 때문입니다

return
commit

대신에

commit
return

하나의 저장 프로 시저에서.


답변

이는 일반적으로 트랜잭션이 시작되고 커밋되지 않았거나 롤백되지 않았을 때 발생합니다.

저장 프로 시저에 오류가 발생하는 경우 예외 처리없이 일부 런타임 오류로 인해 트랜잭션이 완료되지 않아 데이터베이스 테이블을 잠글 수 있습니다. 아래와 같이 예외 처리를 사용할 수 있습니다. SET XACT_ABORT

SET XACT_ABORT ON
SET NoCount ON
Begin Try
     BEGIN TRANSACTION
        //Insert ,update queries
     COMMIT
End Try
Begin Catch
     ROLLBACK
End Catch

출처


답변

중첩 된 트랜잭션을 사용하는 경우 ROLLBACK 작업은 가장 바깥쪽에있는 트랜잭션을 포함하여 모든 중첩 된 트랜잭션을 롤백합니다.

TRY / CATCH와 함께 사용하면 설명 된 오류가 발생할 수 있습니다. 여기에서 더 많은 것을 보십시오 .


답변

저장 프로 시저가 트랜잭션을 연 후 컴파일 실패 (예 : 테이블을 찾을 수 없음, 잘못된 열 이름)가 발생하는 경우에도 발생할 수 있습니다.

Remus Rusanu가 설명한 것과 비슷한 논리를 사용하여 “worker”하나와 try / catch가있는 래퍼 하나를 2 개의 저장 프로 시저를 사용해야한다는 것을 알았습니다. 작업자 캐치는 “정상적인”실패를 처리하는 데 사용되며 래퍼 캐치는 컴파일 실패 오류를 처리하는 데 사용됩니다.

https://msdn.microsoft.com/en-us/library/ms175976.aspx

TRY… CATCH 구문의 영향을받지 않는 오류

다음 유형의 오류는 TRY… CATCH 구문과 동일한 실행 수준에서 발생할 때 CATCH 블록에서 처리되지 않습니다 .

  • 구문 오류와 같은 컴파일 오류배치 실행을 방해하는 .
  • 지연된 이름 확인으로 인해 컴파일 후 발생하는 개체 이름 확인 오류와 같이 문 수준 재 컴파일 중에 발생하는 오류입니다.

다른 사람이 디버깅 시간을 절약하는 데 도움이되기를 바랍니다.


답변

내 경우에는 오류가 발생되고 있던 RETURN내부 BEGIN TRANSACTION. 그래서 나는 다음과 같은 것을 가졌습니다.

Begin Transaction
 If (@something = 'foo')
 Begin
     --- do some stuff
     Return
 End
commit

다음과 같아야합니다.

Begin Transaction
 If (@something = 'foo')
 Begin
     --- do some stuff
     Rollback Transaction ----- THIS WAS MISSING
     Return
 End
commit


답변

광범위한 디버깅 후 저에게 수정은 간단한 누락이었습니다. 롤백 후 catch의 문. 그것 없이는이 추악한 오류 메시지가 당신이 끝낼 것입니다.

begin catch
    if @@trancount > 0 rollback transaction;
    throw; --allows capture of useful info when an exception happens within the transaction
end catch