programing

sql try/message rollback/commit - 롤백 후 잘못된 커밋 방지

linuxpc 2023. 7. 5. 20:29
반응형

sql try/message rollback/commit - 롤백 후 잘못된 커밋 방지

트랜잭션과 try/catch 블록이 있는 MS SQL 스크립트를 작성하려고 합니다.예외가 발생하면 트랜잭션이 롤백됩니다.그렇지 않으면 트랜잭션이 커밋됩니다.나는 몇 가지 다른 웹사이트에서 이렇게 하라고 말하는 것을 보았습니다.

begin transaction
begin try
    --main content of script here
end try
begin catch
    rollback transaction
end catch

commit transaction

하지만 예외를 잡아도 여전히 '커밋 거래' 선을 넘지 않을까요?트랜잭션이 이미 롤백되었기 때문에 SQL 오류가 발생하지 않습니까?저는 다음과 같이 해야 한다고 생각합니다.

declare @success bit = 1

begin transaction
begin try
    --main content of script here
end try
begin catch
    rollback transaction
    set @success = 0
end catch

if(@success = 1)
begin
    commit transaction
end

일반적으로 게시되는 솔루션에 @success 변수가 포함되지 않는 이유는 무엇입니까?이미 롤백된 트랜잭션을 커밋한 결과 발생하는 sql 오류는 없습니까?예외가 발생할 경우 첫 번째 코드 예제의 "커밋 트랜잭션" 행이 여전히 타격을 받을 것이라는 제 말이 틀렸습니까?

저는 항상 이것이 그 주제에 대한 더 나은 기사 중 하나라고 생각했습니다.여기에는 다음과 같은 예가 포함되어 있으며 신뢰할 수 있는 중첩 트랜잭션에 필요한 자주 간과되는 @@trancount가 포함되어 있습니다.

PRINT 'BEFORE TRY'
BEGIN TRY
    BEGIN TRAN
     PRINT 'First Statement in the TRY block'
     INSERT INTO dbo.Account(AccountId, Name , Balance) VALUES(1, 'Account1',  10000)
     UPDATE dbo.Account SET Balance = Balance + CAST('TEN THOUSAND' AS MONEY) WHERE AccountId = 1
     INSERT INTO dbo.Account(AccountId, Name , Balance) VALUES(2, 'Account2',  20000)
     PRINT 'Last Statement in the TRY block'
    COMMIT TRAN
END TRY
BEGIN CATCH
    PRINT 'In CATCH Block'
    IF(@@TRANCOUNT > 0)
        ROLLBACK TRAN;

    THROW; -- raise error to the client
END CATCH
PRINT 'After END CATCH'
SELECT * FROM dbo.Account WITH(NOLOCK)
GO

첫 번째 예제에서는 당신이 맞습니다.일괄 처리는 시도 차단이 실행되는지 여부에 관계없이 커밋 트랜잭션에 도달합니다.

당신의 두 번째 예에서, 저는 다른 논평가들의 의견에 동의합니다.성공 플래그를 사용할 필요가 없습니다.

저는 다음과 같은 접근법이 기본적으로 가벼운 모범 사례 접근법이라고 생각합니다.

예외 처리 방법을 보려면 두 번째 삽입의 값을 255에서 256으로 변경합니다.

CREATE TABLE #TEMP ( ID TINYINT NOT NULL );
INSERT  INTO #TEMP( ID ) VALUES  ( 1 )

BEGIN TRY
    BEGIN TRANSACTION

    INSERT  INTO #TEMP( ID ) VALUES  ( 2 )
    INSERT  INTO #TEMP( ID ) VALUES  ( 255 )

    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    DECLARE 
        @ErrorMessage NVARCHAR(4000),
        @ErrorSeverity INT,
        @ErrorState INT;
    SELECT 
        @ErrorMessage = ERROR_MESSAGE(),
        @ErrorSeverity = ERROR_SEVERITY(),
        @ErrorState = ERROR_STATE();
    RAISERROR (
        @ErrorMessage,
        @ErrorSeverity,
        @ErrorState    
        );
    ROLLBACK TRANSACTION
END CATCH

SET NOCOUNT ON

SELECT ID
FROM #TEMP

DROP TABLE #TEMP

나는 아래의 msql 스크립트 패턴을 여러 번 성공적으로 사용했는데, 이 패턴은 Try-Catch, Commit Transaction-Rollback Transaction, Error Tracking을 사용합니다.

TRY 블록은 다음과 같습니다.

 BEGIN TRY
 BEGIN TRANSACTION T
 ----
 //your script block
 ----
 COMMIT TRANSACTION T 
 END TRY

CATCH 블록은 다음과 같습니다.

BEGIN CATCH
DECLARE @ErrMsg NVarChar(4000), 
        @ErrNum Int, 
        @ErrSeverity Int, 
        @ErrState Int, 
        @ErrLine Int, 
        @ErrProc NVarChar(200)
 SELECT @ErrNum = Error_Number(), 
       @ErrSeverity = Error_Severity(), 
       @ErrState = Error_State(), 
       @ErrLine = Error_Line(), 
       @ErrProc = IsNull(Error_Procedure(), '-')
 SET @ErrMsg = N'ErrLine: ' + rtrim(@ErrLine) + ', proc: ' + RTRIM(@ErrProc) + ', 
       Message: '+ Error_Message()

롤백 스크립트는 다음과 같이 CATCH 블록의 일부가 됩니다.

IF (@@TRANCOUNT) > 0 
BEGIN
PRINT 'ROLLBACK: ' + SUBSTRING(@ErrMsg,1,4000)
ROLLBACK TRANSACTION T
END
ELSE
BEGIN
PRINT SUBSTRING(@ErrMsg,1,4000);   
END

END CATCH

위의 여러 스크립트 블록을 하나의 블록으로 사용해야 합니다.TRY 블록에서 오류가 발생하면 CATCH 블록으로 이동합니다.여기에서는 오류 번호, 오류 심각도, 오류 라인 등에 대한 다양한 세부 정보를 설정합니다.마침내 이러한 모든 세부 정보가 @ErrMsg 매개 변수에 추가됩니다.그런 다음 트랜잭션 수(@@TRANCOUNT > 0)를 확인합니다. 즉, 롤백을 위한 트랜잭션이 있는지 확인합니다.해당 메시지가 있으면 오류 메시지와 ROLBOLLBACK TRANSACTION을 표시합니다.그렇지 않으면 오류 메시지를 인쇄합니다.

TRY 블록의 모든 코드가 성공적으로 실행된 후에만 트랜잭션(데이터베이스의 최종 변경)을 커밋할 수 있도록 COMMIT TRANSACTION T 스크립트를 TRY 블록의 마지막 줄에 보관했습니다.

트랜잭션 카운터

--@@TRANCOUNT = 0
begin try
--@@TRANCOUNT = 0
BEGIN TRANSACTION tran1
 --@@TRANCOUNT = 1

        --your code
        -- if failed  @@TRANCOUNT = 1
        -- if success @@TRANCOUNT = 0

COMMIT TRANSACTION tran1

end try

begin catch
    print 'FAILED'
end catch

아래가 유용할 수 있습니다.

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

BEGIN TRANSACTION;

BEGIN TRY
    -- your code --
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
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO

언급URL : https://stackoverflow.com/questions/25146656/sql-try-catch-rollback-commit-preventing-erroneous-commit-after-rollback

반응형