Error - transaction error

topics 300-백엔드개발 305 데이터베이스
types 에러해결
tags #transaction #spring #database

Transaction Error

트랜잭션 관련 에러는 대부분 전파(Propagation) 설정 문제거나 롤백 조건을 제대로 이해 못해서 생긴다.

상황

서비스 로직에서 @Transactional 붙였는데 롤백이 안 되거나, 반대로 롤백되면 안 되는데 롤백되는 경우.

자주 발생하는 문제들

1. Checked Exception은 롤백 안 됨

@Transactional
public void doSomething() throws IOException {
    repository.save(entity);
    throw new IOException("파일 에러");  // 롤백 안 됨!
}

Spring @Transactional은 기본적으로 RuntimeException만 롤백한다.

해결:

@Transactional(rollbackFor = Exception.class)
public void doSomething() throws IOException {
    // 이제 모든 예외에서 롤백됨
}

2. 같은 클래스 내부 호출은 트랜잭션 안 탐

public void outer() {
    inner();  // 트랜잭션 적용 안 됨!
}

@Transactional
public void inner() {
    // ...
}

왜 이렇냐면: Spring AOP는 프록시 기반이라 외부에서 호출해야 프록시를 거친다. 내부 호출은 프록시를 우회함.

해결:

  • 별도 클래스로 분리
  • self.inner() 패턴 사용 (자기 자신 주입)

3. Propagation 설정 문제

@Transactional
public void parent() {
    try {
        child();
    } catch (Exception e) {
        // 예외 잡았으니 괜찮겠지?
    }
}

@Transactional  // 기본: REQUIRED
public void child() {
    throw new RuntimeException();  // 전체 롤백됨!
}

REQUIRED는 부모 트랜잭션에 참여하기 때문에, child에서 예외 터지면 트랜잭션 자체가 rollback-only로 마킹된다.

해결:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void child() {
    // 별도 트랜잭션으로 분리
}

디버깅 팁

# <span id="applicationyml"></span>application.yml
logging:
  level:
    org.springframework.transaction: DEBUG
    org.springframework.orm.jpa: DEBUG

트랜잭션 시작/커밋/롤백 로그 확인 가능.

결론

  • Checked Exception 롤백하려면 rollbackFor 명시
  • 내부 호출은 트랜잭션 안 탄다
  • REQUIRES_NEW는 신중하게 (커넥션 2개 씀)