ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 체크예외와 언체크(런타임) 예외에서의 트랜잭션
    스프링/스프링 기초DB 2023. 4. 1. 15:48

    스프링에서 체크 예외와 언체크 예외에서의 트랜잭션이 다르게 진행된다.

     

    체크 예외 : 비즈니스 의미가 있을 때 사용

    언체크 예외 : 복구 불가능한 예외

     

    체크 예외일 때는 트랜잭션이 커밋되고 언체크 예외에서는 트랜잭션이 롤백된다.

    @Transactional(rollbackFor = MyException.class)

    물론 체크 예외에서도 롤백을 하고 싶다면 위와 같이 rollbackFor을 넣어주면 롤백을 하게된다.

     

     

     

     

    OrderService.class

    @Slf4j
    @Service
    @RequiredArgsConstructor
    public class OrderService {
    
        private final OrderRepository orderRepository;
    
        // JPA는 트랜잭션 커밋 시점에 Order 데이터를 DB에 반영한다.
        @Transactional
        public void order(Order order) throws NotEnoughMoneyException {
            log.info("order 호출");
            orderRepository.save(order);
    
            log.info("결제 프로세스 진입");
            if (order.getUsername().equals("예외")) {
                log.info("시스템 예외 발생");
                throw new RuntimeException("시스템 예외");
    
            } else if (order.getUsername().equals("잔고부족")) {
                log.info("잔고 부족 비즈니스 예외 발생");
                order.setPayStatus("대기");
                throw new NotEnoughMoneyException("잔고가 부족합니다");
    
            } else {
                // 정상 승인
                log.info("정상 승인");
                order.setPayStatus("완료");
            }
            log.info("결제 프로세스 완료");
        }
    }

    NotEnoughMondyException는 별도로 만든 체크 예외이다.

     

    런타임 예외가 발생했을 때에 롤백이 무조건 이루어진다. 체크 예외가 발생했을 때에는 커밋이 이루어지며 별도의 설정이 있지 않다면 롤백되지 않는다.

     

    @Test
    void runtimeException() {
        // given
        Order order = new Order();
        order.setUsername("예외");
    
        // when
        Assertions.assertThatThrownBy(() -> orderService.order(order))
                        .isInstanceOf(RuntimeException.class);
    
        // then
        Optional<Order> orderOptional = orderRepository.findById(order.getId());
        assertThat(orderOptional.isEmpty()).isTrue();
        // 롤백되어서 데이터가 없어짐
    }

    테스트코드에서 런타임 예외가 발생했을 때를 실행시켜보면 롤백되어서 아예 데이터가 존재하지 않는다.

     

    @Test
    void bizException() {
        // given
        Order order = new Order();
        order.setUsername("잔고부족");
    
        // when
        try {
            orderService.order(order);
        } catch (NotEnoughMoneyException e) {
            log.info("고객에게 잔고 부족을 알리고 별도의 계좌로 입금하도록 안내");
        }
    
        // then
        Order findOrder = orderRepository.findById(order.getId()).get();
        assertThat(findOrder.getPayStatus()).isEqualTo("대기");
    }

    반면에 잔고부족인 경우의 체크 예외가 발생했을 때에는 롤백되지 않고 데이터가 남아져있으며 고객에서 별도의 안내를 하도록 try-catch가 된 것을 확인할 수 있다.

     

     

    런타임 예외는 복구 불가능한 예외로 인지되기때문에 무조건 롤백이 되는 반면에 체크 예외는 롤백이 안되고 커밋된다는 것을 알 수 있다.

Designed by Tistory.