독립성 수준은 일반적으로 ISOLATION_DEFAULT를 사용한다. 이는 사용하는 데이터베이스가 제공하는 기본 독립성 수준을 사용하는 것이다. 사실 독립성 수준은 응용 프로그램의 영역보다는 DB 차원에서 결정할 일이기 때문에 건드리지 않는 것을 권장한다.
rollback 관련 규칙
T.X 내에서 RuntimeException 계열의 unchecked exception이 발생되면 자동으로 rollabck 된다. 이 동작을 재정의하기 위해서 rollbackFor와 noRollbackFor 등이 사용될 수 있다.
rollbackFor나 rollbackForClassName은 checked exception 중에서 rollback 대상이 되는 예외를 설정한다. 반대로 noRollbackFor나 noRollbackForClassName은 unchecked exception 중에서 rollback 하지 않고 commit 할 대상을 설정할 수 있다.
@Transactional(noRollbackFor = ArithmeticException.class)
public void noRollbackForTest(Todo todo) {
repo.save(todo);
int i = 1/0;
}
위 메서드는 ArithmeticException을 발생시키지만 rollback 대상에서 제외된 상태이다.
@Test
@DisplayName("noRollbackForTest")
public void noRollbackForTest() {
Todo sample = Todo.builder().content("test todo").build();
assertThrows(ArithmeticException.class, () -> service2.noRollbackForTest(sample));
assertNotNull(service.select(sample.getId()));
}
메서드를 호출해보면 예외는 발생하지만 저장한 데이터는 잘 확인된다.
timeout 속성
T.X가 취소되는 만료 시간을 초 단위로 지정할 수 있다. timeout은 Propagation 속성이 REQUIRED나 REQUIRES_NEW으로 설정된 상황에서 새롭게 시작되는 T.X에만 적용된다.
@Transactional(timeout = 2)
public void timeoutMethod(Todo todo) {
repo.save(todo);
}
readOnly 속성
readOnly속성은 해당 트랜젝션이 읽기 전용임을 나타낸다. 따라서 insert 쿼리등을 수행할 수 없다.
이를 통해 데이터베이스 성능을 최적화할 수 있다.
일단 DB 차원에서는 읽기 전용 T.X에 대해서는 undo 로그가 필요 없고 이를 위한 공간도 절약할 수 있다. lock 획득 부분에서도 일반적으로 읽을 때는 공유락을 사용하지만 일부 DBMS는 락 자체를 획득하지 않는다. 따라서 처리량을 향상시킬 수 있고 데드락 현상도 걱정할 필요가 없다.
JPA에서는 dirty checking을 수행하지 않는다. 따라서 스냅샷도 찍지 않을꺼고 연관해서 메모리 사용도 줄어들게 된다.
@Transactional(noRollbackFor = ArithmeticException.class,readOnly = true)
public void noRollbackForTest(Todo todo) {
repo.save(todo);
int i = 1 / 0;
}
그렇다고 해서 단순 select 쿼리에서 @Transactional(readOnly=true) 옵션으로 사용하는 것이 생략하는 것보다 언제나 유리하다라는 이야기는 아니다. JPA의 경우 대량의 엔티티를 조회하거나 1차캐시를 이용하는 경우 등은 readOnly=true를 이용해서 P.C를 사용하는게 유리할 수도 있지만 그렇지 않은 경우는 아예 트랜젝션 관리를 안하는 것이 유리할 수도 있다. 상황에 따라 케.바.케다.