ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] 트랜잭션
    Spring 2025. 4. 17. 11:15

     

    minecraft-font

    #Transaction

    💡 Spring 정리: Transaction

    📘 개념 정리

    🔥 Transaction

    • 트랜잭션(Transaction) 데이터 베이스 작업의 최소 단위
         여러 개의 작업을 한 번에 처리하거나, 전부 되돌리는 단위이다.

    •     ex) 은행 이체 → A 계좌 출금 + B 계좌 입금 = 하나의 트랜잭션
          결과: “전부 성공하거나, 전부 실패해야 한다!”

      언제 사용하는가?

    •      여러개의 SQL 또는 JPA  연산 등등 하나의 코드 블럭 안에서 동시에 실행 될때, 사용한다.
    •      예를 들어 내용 저장, 이미지 저장, 태그 저장 같은 작업이 동시에 실행되다가 중간에 하나라도
           실패하면 트랜잭션 롤백(전체 작업을 취소 한다.) 시켜준다.
    •       비정상적으로 저장된 데이터를 막고, 마치 이 작업이 수행된적이 없던 것처럼 처리할수 있다.

     

       트랜잭션의 특징 (ACID)

    속성 설명
    Atomicity (원자성) 모두 수행되거나, 전혀 수행되지 않아야 함
    Consistency (일관성) 트랜잭션 전후에 데이터는 일관된 상태 유지
    Isolation (격리성) 동시에 실행되는 트랜잭션은 서로 간섭하면 안 됨
    Durability (지속성) 커밋된 내용은 영구히 저장돼야 함

     

     

      트랜잭션 명령어 정리

    명령어 기능 설명
    BEGIN / START TRANSACTION 트랜잭션 시작 생략되는 경우도 많음
    COMMIT 트랜잭션 확정 데이터베이스에 반영
    ROLLBACK 트랜잭션 취소 직전 상태로 되돌림
    SAVEPOINT 중간 저장점 설정 특정 시점까지 되돌릴 수 있음
    ROLLBACK TO SAVEPOINT 특정 지점으로 롤백 전체가 아닌 부분 취소 가능

     

     

    🔥 Transaction 전파

    • 하나의 트랜잭션 안에서 다른 트랜잭션이 호출될 때, 어떤 방식으로 연결될지를 결정하는 개념

    • Spring의 @Transactional은 내부적으로 AOP 기반으로 동작하며, 같은 클래스 내부 호출에는 적용되지 않는다.

    • 메서드 호출 시 전파 속성(Propagation) 에 따라 트랜잭션을 공유하거나 분리함

      주요 전파 옵션 (Spring 기준 @Transactional)

     

    propation 속성 설명
    REQUIRED
    (Default) 
    기존 트랜잭션이 있다면 기존 트랜잭션을 사용한다.

    기존 트랜잭션이 없다면 트랜잭션을 새로 생성한다.
    일반적인 서비스 메서드에 사용.
    트랜잭션을 공유하면서 원자성을 보장
    REQUIRED
    _NEW
    항상 새로운 트랜잭션을 시작하고, 기존의 트랜잭션은 보류한다.

    두 트랜잭션은 독립적으로 동작한다.
    예외가 터져도 별개로 로그 저장
    꼭 해야 할 때!
    SUPPORTS
    기존 트랜잭션이 있으면 해당 트랜잭션을 사용한다.

    기존 트랜잭션이 없으면 트랜잭션 없이 실행한다.
    단순 조회 등, 트랜잭션 여부에 민감하지
    않은 상황.
    NOT_
    SUPPORTS
    기존 트랜잭션이 있어도 트랜잭션을 중단하고
    트랜잭션 없이 실행된다.
    배치 처리나 외부 시스템 호출 등에서 굳이
    트랜잭션 필요 없는 경우.
    MANDATORY 기존 트랜잭션이 반드시 있어야한다.

    트랜잭션이 없으면 실행하지 않고 예외를 발생시킨다.
    반드시 트랜잭션 내부에서만 실행되어야 할
    보안/감사 로그 등의 민감한 처리.
    NEVER
    트랜잭션 없이 실행되어야 한다.

    트랜잭션이 있으면 예외를 발생시킨다.
    트랜잭션 사용 자체가 위험한, 예컨대 외부
    API 호출 전에 검증만 할 때.
    NESTED
    현재 트랜잭션 내에서 중첩 트랜잭션을 생성한다.

    중첩 트랜잭션은 독립적으로 롤백할 수 있다.


    기존 트랜잭션이 Commit되면 중첩 트랜잭션도
    Commit 된다.
    하나의 작업 중 일부만 실패해도 그 부분만
    롤백하고 나머지 유지하고 싶을 때.

     

    🔄 동작 흐름

            Transactional 동작

    기본 전파 (REQUIRED)

    // AService
    @Transactional
    public void doA() {
        bService.doB(); // BService도 @Transactional → 같은 트랜잭션 공유
    }
    
    // BService
    @Transactional
    public void doB() {
        // A와 같은 트랜잭션 안에서 실행됨
    }

     

    REQUIRES_NEW 적용 시

    // BService
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void doB() {
        // A의 트랜잭션 중단 → 새로운 트랜잭션 시작
    }

     

    ⚠️ 실수 및 주의사항

    • 같은 클래스 안의 내부 호출은 AOP가 적용되지 않음 → 트랜잭션 적용되지 않음!

    • 트랜잭션 경계는 보통 서비스(public) 메서드 단위로 설정 → private 메서드엔 붙여도 무의미함

    • REQUIRES_NEW는 별도 트랜잭션이므로 실패 시 rollback이 분리됨 → 신중히 사용

    ✨ 팁 & 인사이트

    📌 핵심 정리:
    "서비스 클래스에 트랜잭션을 붙이는 게 맞는 걸까? 레포지토리에도 붙여야 할까?"
    👉 결론은 서비스 클래스에 붙이는 것이 원칙이다.

    - 트랜잭션은 "비즈니스 흐름 단위"를 처리하는 Service 클래스에 선언해야 한다.

    - Repository는 단순 CRUD 수행자일 뿐이며, 상위 트랜잭션의 전파 대상이다.

    - Service는 하나의 유스케이스(회원가입, 주문 등)를 처리하는 단위이므로 트랜잭션 경계를 관리할 책임이 있다. .
    • 1 유스케이스 = 1 트랜잭션"으로 생각하고 큰 흐름에서 관리
      ※ 유스케이스 : 하나의 기능 흐름 (예: 회원가입, 주문 처리 등)은 하나의 트랜잭션으로 감싸는 것이 바람직하다"

    • 하위 기능은 트랜잭션 전파에 의존하게 설계 (불필요하게 중복 선언하지 않기)

    • 전파 속성을 바꿔야 할 이유가 명확하지 않다면 기본값(REQUIRED) 유지!



    🔗 참고 자료

    Spring 정리 내용

    // 예시 코드@PostConstructpublic void init() {    System.out.println("초기화");}  
     

    'Spring' 카테고리의 다른 글

    [Spring] ArgumentResolver  (0) 2025.04.17
    [Spring] HttpMessageConverter  (0) 2025.04.17
    [Spring] 고아 객체  (0) 2025.04.17
    [Spring] 영속성 전이 (Cascade)  (0) 2025.04.17
    [Spring] 지연로딩, 즉시 로딩  (0) 2025.04.16
Designed by Tistory.