아래의 메소드를 보시면 모든 것이 제대로 흘러 가는 것을 볼 수가 있습니다.
public void verifyAndUpdateUniverse(Integer universeId, UniverseDto universeDto) {
Universe universe = universeRepository.getOne(universeId);
universe.setUniverseName(universeDto.getUniversename());
if (!universeDto.getUniverseName().equals("Invalid Universe")) {
universeRepository.save(universe);
}
}
하지만 @Transactional
어노테이션을 붙이면 어떻게 될까요?
@Transactional
public void verifyAndUpdateUniverse(Integer universeId, UniverseDto universeDto) {
Universe universe = universeRepository.getOne(universeId);
universe.setUniverseName(universeDto.getUniversename());
if (!universeDto.getUniverseName().equals("Invalid Universe")) {
universeRepository.save(universe);
}
}
만약 @Transactional
어노테이션을 메소드나 클래스에 붙이게 되면, 모든 변경 사항들은 해당 메소드가 끝날 경우에 데이터베이스로 반영이 됩니다.
즉, 위의 코드를 보시면 if
조건문을 만족하지 않아도 해당 엔티티의 변경사항은 데이터베이스로 반영이 됩니다.
위의 코드를 수정해서 if
조건문을 만족한다면 예외를 던지는 구조로 바꿔보았습니다.
@Transactional
public void verifyAndUpdateUniverse(Integer universeId, UniverseDto universeDto) {
Universe universe = universeRepository.getOne(universeId);
universe.setUniverseName(universeDto.getUniversename());
if (!universeDto.getUniverseName().equals("Invalid Universe")) {
throw new InvalidUniverseException();
}
}
예외 클래스는 아래와 같습니다.
public class InvalidUniverseException extends Exception {
...
}
그래서 위의 코드를 실행하게 되면 예외를 던진다 하더라도 Rollback은 실행되지 않습니다. 그 이유는 Rollback은 기본적으로 Unchecked Exception
에만 실행됩니다.
그래서 우리가 생각하던대로 실행되기 위해서는 @Transactional
의 파라미터로 rollbackOn
을 줘서 Rollback 을 시켜줄 Checked Exception
지정해주면 됩니다.
@Transactional(rollbackOn = InvalidUniverseException.class)
public void verifyAndUpdateUniverse(Integer universeId, UniverseDto universeDto) {
Universe universe = universeRepository.getOne(universeId);
universe.setUniverseName(universeDto.getUniversename());
if (!universeDto.getUniverseName().equals("Invalid Universe")) {
throw new InvalidUniverseException();
}
}
반대로 dontRollbackOn
파라미터를 줘서 특정 Unchecked Exception
이 발생하게 되면 Rollback을 실행시키지 않도록 해줄 수도 있습니다.