Post

Spring 예외 전파여부에 따른 트랜잭션 롤백처리

Spring 예외 전파여부에 따른 트랜잭션 롤백처리

Case 1

1
2
3
4
5
6
7
8
9
10
11
@Transactional
public void insertPopularMovies() { 
  PopularMoviePageResponse res = getPopularMovies(1);
  movieRepository.saveAll(
      res.results().stream()
          .map(item -> MovieEntity.of(item, 1))
          .toList()
  );
  PopularMoviePageResponse res2 = getPopularMovies(2);
  tmdb2Service.insertPopularMovies2(res2);
}
1
2
3
4
5
6
7
8
9
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertPopularMovies2(PopularMoviePageResponse res) {
  movieRepository.saveAll(
      res.results().stream()
          .map(item -> MovieEntity.of(item, 2))
          .toList()
  );
  throw new RuntimeException();
}
  • insertPopularMovies에서 insertPopularMovies2를 호출한 형태
  • insertPopularMovies2에서 임의로 RuntimeException을 throw 했다.
  • insertPopularMovies2에서 REQUIRES_NEW에 의해 트랜잭션이 분리되었어도 insertPopularMovies2의 RuntimeException()으로 인해 예외가 상위 메소드로 전파되어 insertPopularMovies의 내용도 롤백됨

Case 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Transactional
public void insertPopularMovies() {
  PopularMoviePageResponse res = getPopularMovies(1);
  movieRepository.saveAll(
      res.results().stream()
          .map(item -> MovieEntity.of(item, 1))
          .toList()
  );
  PopularMoviePageResponse res2 = getPopularMovies(2);
  try {
    tmdb2Service.insertPopularMovies2(res2);
  } catch (Exception e) {
    log.info(e.getMessage());
  }
}
1
2
3
4
5
6
7
8
9
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertPopularMovies2(PopularMoviePageResponse res) {
  movieRepository.saveAll(
      res.results().stream()
          .map(item -> MovieEntity.of(item, 2))
          .toList()
  );
  throw new RuntimeException();
}
  • insertPopularMovies에서 insertPopularMovies2를 호출한 형태
  • 이번엔 insertPopularMovies2를 try catch로 묶어서 호출
  • catch에서 log만 찍고 exception을 throw하지 않으므로 insertPopularMovies에서 작업한 내용은 롤백되지 않는다. (insertPopularMovies2에서 작업한 내용만 롤백됨.)

Case 3

1
2
3
4
5
6
7
8
9
10
11
12
@Transactional
public void insertPopularMovies() {
  PopularMoviePageResponse res = getPopularMovies(1);
  movieRepository.saveAll(
      res.results().stream()
          .map(item -> MovieEntity.of(item, 1))
          .toList()
  );
  PopularMoviePageResponse res2 = getPopularMovies(2);
  tmdb2Service.insertPopularMovies2(res2);
  throw new RuntimeException();
}
1
2
3
4
5
6
7
8
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertPopularMovies2(PopularMoviePageResponse res) {
  movieRepository.saveAll(
      res.results().stream()
          .map(item -> MovieEntity.of(item, 2))
          .toList()
  );
}
  • insertPopularMovies에서 insertPopularMovies2를 호출한 형태
  • 이번엔 insertPopularMovies2 작업까지 마치고 insertPopularMovies의 마지막 부분에서 RuntimeException을 throw 했다.
  • 이 경우, insertPopularMovies2는 새로운 트랜잭션으로 묶여서 commit 까지 완료되었으므로 롤백되지 않고 insertPopularMovies에서 작업한 내용만 롤백된다.
This post is licensed under CC BY 4.0 by the author.