Entity LifeCycle ( 생명주기 ) 에서 잠시 다루었던 Transactional 을 더 다루어 볼까 합니다.
간단하게 짚고 갑시다.
Checked Exception 의 경우에는 RollBack이 일어나지 않습니다.
그렇다면 Checked Exception 의 경우에도 롤백을 설정하고 싶다면!@Transactional(rollbackFor = Exception.class)
위와 같이 롤백시키고 싶은 예외 Class를 지정해 주면 됩니다.
여러개로 설정이 가능하기도 합니다.
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
private final AuthorRepository authorRepository;
@Transactional
public void putBookAndAuthor() {
Book book = new Book();
book.setName("JPA 시작하기");
bookRepository.save(book);
Author author = new Author();
author.setName("martin");
authorRepository.save(author);
throw new RuntimeException("오류가 나서 DB commit 이 발생하지 않습니다.");
}
}
위와 같은 BookService 라는 서비스를 하나 생성합니다.
@SpringBootTest
class BookServiceTest {
@Autowired
private BookService bookService;
@Autowired
private BookRepository bookRepository;
@Autowired
private AuthorRepository authorRepository;
@DisplayName("1. transactionTest ")
@Test
void test_1(){
try {
bookService.putBookAndAuthor();
} catch (RuntimeException e) {
System.out.println(">>>> " + e.getMessage());
}
System.out.println("books : " + bookRepository.findAll());
System.out.println("authors : " + authorRepository.findAll());
}
}
그리고 JUINT테스트( transactionTest ) 를 생성합니다.
테스틀 실행해보면 당연히! 예외발생에 롤백이 생기겠죠?
books : []
authors : []
다음과 같이 빈 배열 (Null) 값이 출력이 됩니다.
그런데 만약 여기서
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
private final AuthorRepository authorRepository;
public void put() {
this.putBookAndAuthor();
}
@Transactional
void putBookAndAuthor() {
Book book = new Book();
book.setName("JPA 시작하기");
bookRepository.save(book);
Author author = new Author();
author.setName("martin");
authorRepository.save(author);
throw new RuntimeException("오류가 나서 DB commit 이 발생하지 않습니다.");
}
}
Transaction 할 putBookAndAuthor를 실행시켜주는
Put이라는 메소드를 만들어서 테스트를 실행시킨다면?
@SpringBootTest
class BookServiceTest {
@Autowired
private BookService bookService;
@Autowired
private BookRepository bookRepository;
@Autowired
private AuthorRepository authorRepository;
@DisplayName("1. transactionTest ")
@Test
void test_1(){
try {
bookService.put();
} catch (RuntimeException e) {
System.out.println(">>>> " + e.getMessage());
}
System.out.println("books : " + bookRepository.findAll());
System.out.println("authors : " + authorRepository.findAll());
}
}
실행 결과는~?
books : [Book(super=BaseEntity(createdAt=2022-08-01T11:39:11.703, updatedAt=2022-08-01T11:39:11.703), id=1, name=JPA 시작하기, category=null, authorId=null)]
authors : [Author(super=BaseEntity(createdAt=2022-08-01T11:39:11.765, updatedAt=2022-08-01T11:39:11.765), id=1, name=martin, country=null)]
위와 같이 롤백이 일어나지 않게됩니다.
그냥 이렇다 하고 외워도 상관은 없습니다만..
스프링 컨테이너에서 실행시킬때 내부에 있는 transaction의 경우는 무시된다고 합니다.