1. 비즈니스 로직 및 테스트 코드
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
private final AuthorRepository authorRepository;
...
@Transactional
void pubBookAndAuthor(){
Book book = new Book();
book.setName("JPA 시작하기");
bookRepository.save(book);
Author author = new Author();
author.setName("martin");
authorRepository.save(author);
throw new RuntimeException("오류가 발생123123");
}
}
@Test
void transactionTest(){
try {
bookService.pubBookAndAuthor();
} catch (RuntimeException e) {
System.out.println(">>> " + e.getMessage());
}
System.out.println("books : " + bookRepository.findAll());
System.out.println("authors : " + authorRepository.findAll());
}
2. 트랜잭션이 발생하지 않는 상황 발생
- 온라인 강의에 @Transactional에 관한 실습 중 아래와 같은 코드로 테스트 코드를 진행
TransactionAspectSupport.java
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
- RuntimeException (UnChecked Exception) 이 발생했는데 catch를 타지 않아 롤백이 되지 않음
3. 해결
- pubBookAndAuthor의 메소드가 default로 선언되어 있는 것이 문제 (public으로 변경)
- default로 선언된 메소드는 트랜잭션 블록으로 인식을 하지 못하고 있음
- public 메소드로 변경하니 트랜잭션이 정상 작동, TransactionAspectSupport.java catch 영역도 정상 작동
@Transactional
//void pubBookAndAuthor(){ 문제..로 수정
public void pubBookAndAuthor(){
Book book = new Book();
book.setName("JPA 시작하기");
bookRepository.save(book);
Author author = new Author();
author.setName("martin");
authorRepository.save(author);
throw new RuntimeException("오류가 발생123123");
}
4. 결론
- 실습으로 메소드 형식을 변경하면서 발생한 일이지만 이로 인해 지나쳐갈 만한 위험한 상황을 겪어 다행이었다..
- 트랜잭션 블록을 이용하려면 protected(선언 X)를 쓰지 말고 꼭 public으로 지정하자!