티스토리 뷰

IT/Spring

🔄 Spring의 @Transactional 완전 정복 - 개념, 원리, 동작 방식, 트러블 슈팅까지

Stv 2025. 6. 11. 19:50

목차



    1.트랜잭션이란?

    하나의 작업 단위를 원자성 있게 처리하기 위한 논리적 작업 묶음
    모두 성공하거나, 하나라도 실패하면 전체를 롤백해야 함

     

    📌 ACID 원칙

    항목 설명
    Atomicity(원자성) 전부 선공 or 전부 실패 (불완전 상태 금지)
    Consistency(일관성) 작업 후 데이터 정합성 보장
    Isolation(격리성) 동시에 실행되는 트랜잭션 간 간섭 없음
    Durability(지속성) 커밋된 트랜잭션은 영구 반영됨

    💉 2. Spring의 @Transational이란?

    Spring AOP 기반으로 구현된 선언적 트랜잭션 처리 방식
    특정 메서드나 클래스에서 트랜잭션 범위와 롤백/커밋 조건을 선언적으로 지정할 수 있음
    @Transactional
    public void order() {
        saveOrder();
        savePayment();
    }

    -> order() 메서드 실행 중 예외 발생 시, 전체 작업을 자동으로 롤백


    3. @Transactional 내부 동작 구조

     

    ✅ AOP 기반 프록시 매커니즘

    Client → [Proxy] → @Transactional Advice → 실제 비즈니스 메서드
    • 실제 메서드 호출 전 -> 트랜잭션 시작
    • 메서드 정상 종료 -> 커밋
    • 런타임 예외 발생 -> 롤백
    • 체크 예외 발생 -> 기본적으로 롤백 X (설정 필요)

    ✅PlatformTransactionManager가 핵심 인터페이스

    • DataSourceTransactionManager (JDBC 기반)
    • JapTransactionManager (JPA 기반)

    4. 실습 예제 (JPA 기준)

    @Service
    public class MemberService {
    
        @Transactional
        public void join(Member member) {
            memberRepository.save(member);
            // 예외 발생 시 전체 롤백
        }
    }

     

    ✅ 클래스 수준에 선언 시 -> 모든 메서드에 적용

    @Transactional
    public class OrderService {
        public void createOrder() { ... }
        public void cancelOrder() { ... }
    }

    5. 전파(Propagation) 옵션

    옵션 설명
    REQUIRED(기본) 기존 트랜잭션 있으면 참여, 없으면 새로 생성
    REQUIRES_NEW 무조건새로운 트랜잭션 생성 (기존은 일시 중단) 
    NESTED 트랜잭션 안에 또 다른 트랜잭션 (Savepoint 사용)
    SUPPORTS 트랜잭션 있으면 참여, 없으면 그냥 실행
    NOT_SUPPORTED 트랜잭션 있으면 일시 중단하고 비트랜잭션 수행
    NEVER 트랜잭션 있으면 예외 발생
    MANDATORY 반드시 트랜잭션 있어야 함 (없으면 예외)

     

    ✅ 실무 예시 : 로깅은 REQUIRES_NEW

    @Transactional(propagation = REQUIRES_NEW)
    public void logError(String msg) { ... }

    6. 고립 수준

    수준  설명 현상 방지
    DEFAULT DB 기본 수준 (대부분 READ_COMMITED) -
    READ_UNCONMMITED 커밋 전 데이터 읽기 가능 Dirty Read 가능
    READ_COMMITED 커밋된 데이터만 읽음 Dirty Read 방지
    REPEATABLE_READ 같은 트랜잭션 내동일 쿼리 결과 유지  Non-repeatable Read 방지
    SERIALIZABLE 가장 엄격, 완전한 격리 Phantom Read 방지
    @Transactional(isolation = Isolation.REPEATABLE_READ)

    7. 롤백 조건

    • 기본 : RuntimeException 또는 Error 발생 시만 롤백
    • CheckedException은 롤백하지 않음 -> 명시 필요
    @Transactional(rollbackFor = Exception.class)

    8. 실무에서 주의할 점

    ✅ 1. 자기 자신 호출 (self-invocation) -> AOP 미적용

    @Transactional
    public void methodA() {
        methodB(); // 같은 클래스 내 호출 = 프록시 우회 → 트랜잭션 적용 안됨
    }

    -> 해결책 : 별도 Bean 분리 또는 AOP-aware 방식 사용

     

    ✅ 2. 비공개 메서드(private)는 트랜잭션 적용 안됨

    • Spring AOP는 public 메서드에만 적용

    ✅ 3. 메서드 내부에서예외 삼키면 롤백되지 않음

    @Transactional
    public void save() {
        try {
            repository.save(); // 예외 발생했지만 catch로 삼킴
        } catch (Exception e) {
            // 롤백 안 됨
        }
    }

     -> TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 호출로 수동 롤백 가능


    ✅ 마무리 요약

    항목 핵심 포인트
    트랜잭션 개념 원자성 보장, ACID 만족
    @Transactional 동작 AOP 기반 프록시 -> PlatformTransactionalManager 제어
    주요 옵션 propagation, isolation, rollbackFor
    실무 이슈 자기 호출, private 메서드, 예외 삼킴 등 주의