본문 바로가기

Spring

@Transactional 내에서 try catch와 rollback 연관성

Spring Framework을 사용하면서 @Transactional 어노테이션에 대해 크게 고민해본 적이 없었다. 트랜잭션 내의 작업에 있어서 원자성을 보장해준다? 정도

(원자성: 하나의 원자 트랜잭션은 모두 성공하거나 또는 실패하는 데이터베이스 운용 집합)

 

오늘 회사에서 업무를 하다가 @Transactional이 선언 된 서비스 내 메서드 실행 시 예외가 발생하였는데 코드를 수정하고 다시 동작시켜보니 이미 데이터가 생성되었단다. DB를 확인해보니 데이터가 rollback되지 않고 들어가 있었다.

 

찾아보니 try내에서 예외 발생 시 catch 처리했을 경우 rollback이 되지 않는다고 한다. 그럼 try catch시 트랜잭션의 원자성은 보장받지 못하는 것일까? 그렇지도 않다.

 

Spring에서 @Transactional 선언 시 기본 속성은 아래와 같다.

@Transactional
//@Transactional(rollbackFor = {RuntimeException.class, Error.class}) 기본 속성
public void save(User user) {
	userRepository.save(user);
}

 

즉, RuntimeException과 Error가 발생했을 경우에는 기본적으로 rollback이 된다는 것.

  -> Exception과 Error에 대해서도 추후 자세히 다루어야겠다.

 

위 두 가지 경우가 아니라면 rollback이 되지 않는다.  하지만 트랜잭션을 rollback 하는 다른 방법들도 있다.

 

1. @Transactional의 옵션 값을 변경

@Transactional(rollbackFor = {Exception.class})
public void save(User user) {
	userRepository.save(user);
}

위와 같이 작성하면 모든 예외에 대해서 rollback 하게 된다. 옵션을 변경해서 rollback이 가능하다는 것.

 

2. RuntimeException을 던짐

@Transactional(rollbackFor = {RuntimeException.class, Error.class})
public void save(User user) {
    try {
        userRepository.save(user);
    } catch(Exception e) {
        throw new RuntimeException("RuntimeException rollback");
    }
}

RuntimeException을 던져주면 @Transactional의 기본 옵션에 해당하기 때문에 예외가 발생한 경우 rollback이 된다.

 

3. 수동으로 rollback

@Transactional(rollbackFor = {RuntimeException.class, Error.class})
public void save(User user) {
    try {
        userRepository.save(user);
    } catch(Exception e) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

Spring Framework에 TransactionAspectSupport 클래스를 이용해 수동으로 rollback 해주는 방법이 있다. 위와 같이 작성하면 Exception 발생 시 해당 메서드를 rollback 시킬 수 있다.

 

** 추가적으로 특정 예외 발생 시 rollback이 되지 않도록 설정하는 방법

@Transactional(noRollbackFor = {RuntimeException.class})
public void save(User user) {
    userRepository.save(user);
}

 

예외가 발생했을 경우에도 rollback을 하는 다양한 방법이 있지만, 어떻게 예외를 처리해 rollback 시키는 것이 좋은 방법인지에 대해서는 많은 고민이 필요할 것 같다.