728x90
반응형
예외가 발생했는데, 내부에서 예외를 처리 못 하고 트랜잭션 범위 밖으로 예외를 던지면 어떻게 될까?
- 예외 발생 시 스프링 트랜잭션 AOP는 예외 종류에 따라 트랜잭션을 커밋하거나 롤백한다.
- 언체크 예외인 RuntimeException, Error와 그 하위 예외가 발생하면 트랜잭션을 롤백한다.
- 체크 예외인 Exception과 그 하위 예외가 발생하면 트랜잭션을 커밋한다.
- 물론 정상 응답(리턴)하면 트랜잭션을 커밋한다.
테스트 코드
@SpringBootTest
public class RollbackTest {
@Autowired
RollbackService rollbackService;
@Test
void runtimeException() {
assertThatThrownBy(() -> rollbackService.runtimeException()).isInstanceOf(RuntimeException.class);
}
@Test
void checkedException() {
assertThatThrownBy(() -> rollbackService.checkedException()).isInstanceOf(MyException.class);
}
@Test
void rollbackFor() {
assertThatThrownBy(() -> rollbackService.rollbackFor()).isInstanceOf(MyException.class);
}
@TestConfiguration
static class RollbackTestConfig {
@Bean
RollbackService rollbackService() {
return new RollbackService();
}
}
@Slf4j
static class RollbackService {
// 런타임 예외 발생: 롤백
@Transactional
public void runtimeException() {
log.info("call runtimeException");
throw new RuntimeException();
}
// 체크 예외 발생: 커밋
public void checkedException() throws MyException {
log.info("call checkedException");
throw new MyException();
}
// 체크 예외 rollbackFor 지정: 롤백
@Transactional(rollbackFor = MyException.class)
public void rollbackFor() throws MyException {
log.info("call rollbackFor");
throw new MyException();
}
}
static class MyException extends Exception {
}
}
runTimeException
2023-12-21T11:21:02.901+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [hello.springtx.exception.RollbackTest$RollbackService.runtimeException]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2023-12-21T11:21:02.902+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(972458732<open>)] for JPA transaction
2023-12-21T11:21:02.902+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@65ff4b8c]
2023-12-21T11:21:02.902+09:00 TRACE 20880 --- [ main] o.s.t.i.TransactionInterceptor : Getting transaction for [hello.springtx.exception.RollbackTest$RollbackService.runtimeException]
2023-12-21T11:21:02.902+09:00 INFO 20880 --- [ main] h.s.e.RollbackTest$RollbackService : call runtimeException
2023-12-21T11:21:02.902+09:00 TRACE 20880 --- [ main] o.s.t.i.TransactionInterceptor : Completing transaction for [hello.springtx.exception.RollbackTest$RollbackService.runtimeException] after exception: java.lang.RuntimeException
2023-12-21T11:21:02.902+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : 2023-12-21T11:21:02.807+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [hello.springtx.exception.RollbackTest$RollbackService.rollbackFor]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-hello.springtx.exception.RollbackTest$MyException
2023-12-21T11:21:02.856+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(1652372991<open>)] for JPA transaction
2023-12-21T11:21:02.863+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@4df13dd0]
2023-12-21T11:21:02.863+09:00 TRACE 20880 --- [ main] o.s.t.i.TransactionInterceptor : Getting transaction for [hello.springtx.exception.RollbackTest$RollbackService.rollbackFor]
2023-12-21T11:21:02.863+09:00 INFO 20880 --- [ main] h.s.e.RollbackTest$RollbackService : call rollbackFor
2023-12-21T11:21:02.864+09:00 TRACE 20880 --- [ main] o.s.t.i.TransactionInterceptor : Completing transaction for [hello.springtx.exception.RollbackTest$RollbackService.rollbackFor] after exception: hello.springtx.exception.RollbackTest$MyException
2023-12-21T11:21:02.864+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : **Initiating transaction rollback**
2023-12-21T11:21:02.864+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Rolling back JPA transaction on EntityManager [SessionImpl(1652372991<open>)]
2023-12-21T11:21:02.866+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(1652372991<open>)] after transaction
2023-12-21T11:21:02.902+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Rolling back JPA transaction on EntityManager [SessionImpl(972458732<open>)]
2023-12-21T11:21:02.902+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(972458732<open>)] after transaction
checkedException
// java17 사용해서 그런지 강의에서는 Initialing transaction commit 출력되는데 실제로는 안나옴!
2023-12-21T11:21:02.897+09:00 INFO 20880 --- [ main] h.s.e.RollbackTest$RollbackService : call checkedException
rollbackFor
2023-12-21T11:21:02.807+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [hello.springtx.exception.RollbackTest$RollbackService.rollbackFor]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-hello.springtx.exception.RollbackTest$MyException
2023-12-21T11:21:02.856+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(1652372991<open>)] for JPA transaction
2023-12-21T11:21:02.863+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@4df13dd0]
2023-12-21T11:21:02.863+09:00 TRACE 20880 --- [ main] o.s.t.i.TransactionInterceptor : Getting transaction for [hello.springtx.exception.RollbackTest$RollbackService.rollbackFor]
2023-12-21T11:21:02.863+09:00 INFO 20880 --- [ main] h.s.e.RollbackTest$RollbackService : call rollbackFor
2023-12-21T11:21:02.864+09:00 TRACE 20880 --- [ main] o.s.t.i.TransactionInterceptor : Completing transaction for [hello.springtx.exception.RollbackTest$RollbackService.rollbackFor] after exception: hello.springtx.exception.RollbackTest$MyException
2023-12-21T11:21:02.864+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : **Initiating transaction rollback**
2023-12-21T11:21:02.864+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : **Rolling back** JPA transaction on EntityManager [SessionImpl(1652372991<open>)]
2023-12-21T11:21:02.866+09:00 DEBUG 20880 --- [ main] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(1652372991<open>)] after transaction
- 기본 정책과 무관하게 특정 예외를 강제로 롤백하고 싶으면 rollbackFor 를 사용하면 된다. (해당 예외의 자식도 포함된다.)
- rollbackFor = MyException.class 을 지정했기 때문에 MyException 이 발생하면 체크 예외이지만 트랜잭션이 롤백된다.
더보기
- 스프링은 기본적으로 체크 예외는 비즈니스 의미가 있을 때 사용하고 런타임(언체크) 예외는 복구 불가능한 예외로 가정하기 때문에 커밋, 롤백 차이가 발생한다.
- 결론적으로 비즈니스 상황에 따라 체크 예외의 경우에도 트랜잭션을 커밋하지 않고, 롤백하고 싶을 때 rollbackFor 옵션을 사용하면 된다.
- 결론적으로 비즈니스 상황에 따라 체크 예외의 경우에도 트랜잭션을 커밋하지 않고, 롤백하고 싶을 때 rollbackFor 옵션을 사용하면 된다.
728x90
반응형
댓글