25.03.07 TIL Transaction

신성훈·2025년 3월 7일
0

TIL

목록 보기
143/162

1. 트랜잭션이란?

트랜잭션은 데이터베이스의 논리적 작업 단위로 하나의 작업을 수행하기 위해 실행되는 일련의 연산들을 의미한다.
트랜잭션은 일관성 유지를 위해 반드시 완료되거나 실패 시 모든 작업이 취소되어야 한다.


2. 트랜잭션의 ACID 특성

트랜잭션은 ACID 원칙을 준수해야 한다.

  1. Atomicity(원자성)

    • 트랜잭션이 완전히 수행되거나 전혀 수행되지 않아야 함
    • 중간에 오류 발생 시 전체가 롤백되어야 함
  2. Consistency(일관성)

    • 트랜잭션 수행 전후로 데이터 무결성이 유지되어야 함
    • 제약 조건을 위반하지 않도록 보장해야 함
  3. Isolation(격리성)

    • 동시에 실행되는 트랜잭션이 서로 간섭하지 않도록 해야 함
    • 트랜잭션 격리 수준을 통해 데이터 충돌 방지 가능
  4. Durability(지속성)

    • 트랜잭션이 성공적으로 완료되면 데이터베이스에 영구적으로 반영되어야 함
    • 시스템 장애가 발생해도 결과가 유지되어야 함

3. Spring에서의 트랜잭션 관리

Spring에서는 @Transactional 어노테이션을 통해 트랜잭션을 쉽게 관리할 수 있다.

기본 사용법

@Service
public class OrderService {
    
    @Transactional
    public void placeOrder(Long userId, Long productId) {
        // 주문 생성
        orderRepository.save(new Order(userId, productId));
        
        // 결제 처리 (여기서 예외 발생 시 롤백됨)
        paymentService.processPayment(userId, productId);
    }
}
  • @Transactional을 메서드에 적용하면 예외 발생 시 자동으로 롤백
  • 정상적으로 실행되면 자동 커밋

트랜잭션 전파 옵션

Spring에서는 트랜잭션이 어떻게 전파될지를 결정할 수 있다.

@Transactional(propagation = Propagation.REQUIRED)
옵션설명
REQUIRED (기본값)기존 트랜잭션이 있으면 참여, 없으면 새 트랜잭션 생성
REQUIRES_NEW항상 새로운 트랜잭션을 생성
SUPPORTS트랜잭션이 있으면 참여, 없으면 트랜잭션 없이 실행
MANDATORY반드시 기존 트랜잭션이 있어야 함 (없으면 예외 발생)
NOT_SUPPORTED트랜잭션 없이 실행
NEVER트랜잭션이 있으면 예외 발생

4. 트랜잭션 격리 수준

트랜잭션이 동시에 실행될 때 데이터 정합성을 보장하기 위해 격리 수준을 설정할 수 있다.

@Transactional(isolation = Isolation.SERIALIZABLE)
격리 수준설명발생할 수 있는 문제
READ_UNCOMMITTED다른 트랜잭션의 커밋되지 않은 변경 내용을 읽을 수 있음Dirty Read
READ_COMMITTED커밋된 데이터만 읽음Non-Repeatable Read
REPEATABLE_READ한 트랜잭션에서 같은 데이터를 여러 번 조회할 때 결과가 동일하게 유지됨Phantom Read
SERIALIZABLE가장 높은 격리 수준, 동시 실행을 막고 순차적으로 처리성능 저하

5. 트랜잭션 롤백 설정

Spring의 @Transactional은 기본적으로 Unchecked Exception(RuntimeException)이 발생하면 롤백된다.

체크 예외도 롤백되도록 설정

@Transactional(rollbackFor = Exception.class)
  • 기본적으로 RuntimeExceptionError만 롤백 대상이므로 Exception까지 롤백하려면 명시적으로 지정해야 함

6. 트랜잭션 사용 시 주의할 점

  1. 프록시 방식이므로 같은 클래스 내에서 메서드 호출 시 트랜잭션이 적용되지 않을 수 있음

    @Transactional
    public void methodA() {
        methodB(); // 같은 클래스 내 호출 → 트랜잭션 적용되지 않음
    }
    • 해결책: AOP 적용을 위해 반드시 다른 빈에서 호출해야 함
  2. Lazy Loading과 트랜잭션 범위

    • @Transactional이 종료되면 영속성 컨텍스트도 닫히므로 Lazy Loading을 사용하려면 주의해야 함
  3. 트랜잭션 범위를 최소화

    • 너무 긴 트랜잭션은 성능 문제를 유발할 수 있으므로 꼭 필요한 부분에서만 트랜잭션을 적용하는 것이 좋음

7. 마무리

Spring에서 트랜잭션을 관리할 때 @Transactional을 사용하면 편리하지만 전파 옵션, 롤백 조건, 격리 수준 등을 잘 이해하고 사용해야 함을 배웠다.
Lazy Loading과 트랜잭션 범위를 고려하지 않으면 예상치 못한 에러가 발생할 수도 있다.
또한 트랜잭션을 최소한의 범위에서 사용해야 성능을 최적화할 수 있다는 점도 중요하다는 걸 다시금 느꼈습니다.

profile
조급해하지 말고, 흐름을 만들고, 기록하면서 쌓아가자.

0개의 댓글