본문 바로가기
● Data Processing

트랜잭션 오류 대응과 재시도 전략

by DataFolio.lab 2026. 6. 9.

MSSQL에서는 트랜잭션을 사용해 여러 DML 작업을 하나의 논리 단위로 묶고 COMMIT으로 확정하거나 ROLLBACK으로 되돌릴 수 있으며, 복잡한 흐름에서는 SAVE TRANSACTION(저장점)을 사용해 부분 되돌리기를 구현할 수 있습니다. 

트랜잭션 오류 대응과 재시도 전략

 


트랜잭션의 기본 개념과 MSSQL에서의 동작

  • 트랜잭션은 원자성, 일관성, 고립성, 지속성(ACID)을 보장하는 논리적 작업 단위입니다. 실패 시 전체를 되돌려 데이터 일관성을 유지합니다.
  • SQL Server에서는 BEGIN TRANSACTION으로 명시적 트랜잭션을 시작하고 COMMIT TRANSACTION으로 확정, ROLLBACK TRANSACTION으로 되돌립니다.
  • SAVE TRANSACTION(저장점)은 트랜잭션 내의 체크포인트로, 저장점까지 부분 롤백이 가능하게 합니다. 저장점 이름은 최대 32자입니다.

핵심 시스템 변수와 상태 확인

  • @@TRANCOUNT: 현재 열린(중첩된 포함) 트랜잭션 수를 보여줍니다; 프로시저에서 상위 트랜잭션 여부 판단에 유용합니다.
  • @@ERROR 대신 TRY...CATCH와 ERROR_MESSAGE()/ERROR_SEVERITY() 등을 사용해 예외를 처리하는 패턴을 권장합니다(TRY/CATCH가 더 현대적이고 명확함).

기본 사용 패턴 — 안전한 트랜잭션 템플릿 (예시)

설명: 아래 패턴은 단일 트랜잭션을 시작해 여러 DML을 실행하고, 오류 발생 시 안전하게 롤백하고 자세한 예외를 다시 던지는 형태입니다. 이 템플릿을 그대로 복사해서 사용하십시오.

BEGIN TRY
BEGIN TRANSACTION

-- 작업 1: 예: 잔액 차감
UPDATE Accounts
SET Balance = Balance - 100
WHERE AccountId = 1;

-- 작업 2: 예: 잔액 증가
UPDATE Accounts
SET Balance = Balance + 100
WHERE AccountId = 2;

-- 선택적 검증: 영향을 받은 행 수 확인
IF @@ROWCOUNT = 0
BEGIN
    THROW 51000, '갱신된 행이 없습니다. 트랜잭션을 롤백합니다.', 1;
END

COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
    ROLLBACK TRANSACTION;

DECLARE @ErrMsg NVARCHAR(4000) = ERROR_MESSAGE();
DECLARE @ErrSeverity INT = ERROR_SEVERITY();
THROW; -- 원래 예외 재발생
END CATCH

(위 패턴에서는 TRY/CATCH와 THROW를 사용하여 원래 오류를 보존하면서 안전하게 롤백합니다.) 


복잡한 트랜잭션: SAVE TRANSACTION(저장점) 사용 예시

설명: 한 트랜잭션 안에서 부분적으로 실패 시 일부만 롤백하고 나머지는 유지해야 할 때 저장점을 사용합니다. 예를 들어, 여러 테이블을 업데이트하되 중간 단계 하나가 실패하면 그 단계만 되돌리고 계속 진행하거나 최종적으로 커밋할 수 있습니다.

BEGIN TRANSACTION

UPDATE Orders SET Status = 'Processing' WHERE OrderId = 123;

SAVE TRANSACTION Save_After_OrderUpdate;

BEGIN TRY
    UPDATE Inventory SET Qty = Qty - 2 WHERE ItemId = 456;
    -- 추가 작업
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION Save_After_OrderUpdate;
    -- 필요시 추가 로직(로그, 경고) 수행
    IF @@TRANCOUNT > 0
        COMMIT TRANSACTION; -- 저장점 이전 작업은 유지하고 전체 트랜잭션 종료
END CATCH

설명: 저장점으로 롤백하면 저장점 전에 수행한 작업(예: 주문 상태 변경)은 유지할 수 있습니다. 


중첩 트랜잭션과 트랜잭션 카운트 처리

  • SQL Server에서 BEGIN TRAN을 여러 번 호출하면 @@TRANCOUNT가 증가하지만 COMMIT은 최종적으로 모든 중첩을 닫을 때까지 실제 커밋이 지연됩니다; 즉 내부 COMMIT은 카운트만 줄일 뿐 최종 확정은 마지막 COMMIT 시점입니다.
  • 프로시저를 호출할 때 상위 트랜잭션이 있는지 @@TRANCOUNT로 확인하고, 상위 트랜잭션이 없으면 프로시저 내부에서 트랜잭션을 시작하고, 있으면 저장점을 만들어 부분 롤백 처리를 설계해야 합니다.

동시성, 잠금, 데드락 고려사항

  • 트랜잭션을 길게 유지하면 잠금 시간이 길어져 동시성 저하와 데드락 가능성이 커집니다. 트랜잭션은 가능한 짧게 유지하고, 필요 시 쿼리 최적화 또는 인덱스 개선으로 락 범위를 줄이십시오.
  • 데드락 발생 시 SQL Server가 한 쪽을 죽여(자동 롤백) 상태를 회복하므로 애플리케이션은 재시도 로직을 준비해야 합니다. 즉, 트랜잭션 실패 시 재시도 정책을 설계해야 합니다.

트랜잭션 격리 수준과 그 영향

  • 기본 격리 수준은 Read Committed(또는 인스턴스 설정에 따라 다름)이며, 격리 수준을 높이면 일관성은 좋아지지만 동시성은 떨어집니다. 필요에 따라 SNAPSHOT이나 REPEATABLE READ 등을 고려하되, 설계상 트레이드오프를 검토해야 합니다.
  • 격리 수준 변경은 트랜잭션 시작 전 SET TRANSACTION ISOLATION LEVEL 문으로 설정합니다. 높은 격리 수준 사용 시 잠금과 성능 영향을 반드시 측정하십시오.

운영 환경에서의 실무 권장사항

  • 트랜잭션은 가능한 한 짧게, 네트워크 왕복이나 사용자 입력 대기 시 트랜잭션을 열지 마십시오.
  • 로그 증가와 백업 정책을 고려: 대량 트랜잭션은 트랜잭션 로그를 빠르게 채울 수 있으므로 주기적 로그 백업 및 배치 사이즈 조절을 권장합니다.
  • 예외 발생 시 상세 로깅(문제 재현 용도)과 재시도 정책(지수 백오프 등)을 구현하십시오.
  • 테스트: 데드락, 동시성, 롤백 시나리오를 포함한 부하 테스트를 진행해 운영 전에 문제를 발견하십시오.

예제: 저장 프로시저에서 안전한 트랜잭션 처리 패턴

설명: 아래 예제는 호출자가 이미 트랜잭션을 열었는지 확인하고, 상황에 따라 저장점을 만들거나 자체 트랜잭션을 시작하는 패턴입니다. 이 코드는 바로 복사해서 사용 가능합니다.

CREATE PROCEDURE dbo.SafeUpdateProcedure
    @Id INT
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @TranCount INT = @@TRANCOUNT;

    IF @TranCount = 0
        BEGIN TRANSACTION;
    ELSE
        SAVE TRANSACTION SP_SavePoint;

    BEGIN TRY
        UPDATE MyTable SET ColA = 'X' WHERE Id = @Id;

        IF @TranCount = 0
            COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
        BEGIN
            IF @TranCount = 0
                ROLLBACK TRANSACTION;
            ELSE
                ROLLBACK TRANSACTION SP_SavePoint;
        END
        THROW;
    END CATCH
END

설명: 프로시저가 상위 트랜잭션 내에서 호출되면 저장점을 사용해 프로시저 내부 오류 시 부분 롤백만 수행합니다. 


FAQ 형태로 정리된 주의사항

  • Q: COMMIT을 깜박하면? A: 열린 트랜잭션은 락을 유지하고 트랜잭션 로그를 증가시킵니다. 반드시 타임아웃/모니터링으로 열린 트랜잭션을 탐지해야 합니다.
  • Q: SAVEPOINT와 RELEASE SAVEPOINT 차이? A: SQL Server는 SAVE TRANSACTION으로 저장점을 만들고, 명시적 RELEASE SAVEPOINT 구문은 없지만 저장점 이름을 더 이상 참조하지 않으면 사실상 무시됩니다(표준 DBMS마다 차이 있음).
  • Q: 트랜잭션이 오래 걸릴 때 대책? A: 쿼리 최적화, 인덱스 튜닝, 배치 사이즈 분할, 격리 수준 조정 등을 적용하십시오.
반응형

놓치면 아쉬운 추천 글, 함께 읽어보세요!

  • 추천 글을 불러오는 중입니다...