묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨스프링 DB 2편 - 데이터 접근 활용 기술
강의의 롤백 커밋 기준에 대해 추가로 궁금한 점이 있습니다.
1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]이전 강의 예외와 트랜잭션 커밋, 롤백 - 기본에서 예외 발생시 트랜잭션 내부에서 예외를 처리하지 못하고, 트랜잭션 범위 밖으로 예외를 던지면,스프링은 기본적으로언체크 예외 = 롤백체크 예외 = 커밋 한다고 배웠습니다.그리고 본 강의 활용에서 체크 예외와 언체크 예외를 통해 커밋과 롤백이 되는 것을 확인할 수 있었는데요.여기서 제가 궁금한 것은 일단 언체크 예외도 명시적으로 던지지 않아도 catch 해서 처리할 수 있다고 알고 있습니다.그러면 스프링이 언체크 예외를 롤백시키는 기준이 트랜잭션 내에서 언체크 예외를 처리하지 못하고 범위 밖으로 던졌을 때에만 롤백하는 것인가요?즉, 해당 트랜잭션 내에서 언체크 예외를 잡아서 처리하면 트랜잭션 범위 밖으로 언체크 예외가 던져졌기 않았기 때문에 해당 트랜잭션이 롤백되지 않고 커밋 되나요?예를 들어 아래의 코드와 같이 트랜잭션은 OrderService의 order() 메서드에서 실행되고, couponService를 통해 주문한 고객에게 쿠폰을 1개 우선 발행한 뒤에, 해당 트랜잭션 내에서 orderRepository.save 를 통해 DB에 주문이 저장됩니다.(주문을 먼저 완료하고 쿠폰을 발행 해야겠지만 제 질문 상황의 명확성을 위해 예시를 이렇게 했습니다.)하지만 orderRepository.save()메서드 실행 도중 DB에 문제가 생겨 Order가 DB에 정상적으로 저장이 되지 않아 Exception이 발생하였고 (언체크 예외) 해당 예외를 잡아서 처리했습니다. 그러면 해당 트랜잭션 밖으로 던져지는 예외는 존재하지 않으며 정상흐름대로 동작합니다. 이 경우 해당 트랜잭션은 롤백되는 것인가요 아니면 커밋되는 것인가요? 1번 질문에서 정상 흐름으로 바뀌었기 때문에 커밋이 된다고 하면,만약 RuntimeException을 잡아 체크 예외로 변경해서 해당 트랜잭션 범위 밖으로 던질 경우도 동일하게 커밋이 되는건가요?@Transactional public void order(Order order) { couponService.giveCoupon(order.getUserId)); try { orderRepository.save(order); } catch (RuntimeException e) { // Exception을 잡아서 처리하는 로직 } }
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
트랜잭션 전파 시 체크 예외를 활용한 복구 처리 관련 문의
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]"회원 가입을 시도한 로그를 남기는데 실패하더라도 회원 가입은 유지 되어야 한다." 이 요구사항을 만족하기 위한 방법1.2 이외에 체크 예외를 활용하는 방법3 관련 문의입니다.방법1. REQUIRES_NEW로 선언해서 물리 트랜잭션 분리방법2. MemberFacade 구조를 사용하여 물리 트랜잭션 분리방법3. 체크 예외를 던져서 오류 관련 내용 커밋(9.스프링 트랜잭 션 이해 / 예외와 트랜잭션 커밋, 롤백 - 활용)질문. 체크예외를 활용하면 코드에 명시적으로 오류 상황에 대 한 처리를 할 수 있어서 개발자가 오류를 코드 레벨에서 인지할 수도 있고 오류를 받을 때 로그 상태를 저장할 수 도 있다는 장점 이 있을 것 같은데 비즈니스 적으로 의미가 있는 경우에는 체크예외를 사용하고 그 외에는 방법1,2를 선택하면 되는지 궁금합니 다. (오류 처리로 서비스 코드를 지저분하게 만들게 하고 싶지 않 는 경우 방법1,2를 사용하는지?)참고) 아래는 위 내용을 테스트 할 때 작성한 코드 입니다.체크예외를 사용하는 서비스 메소드 내용@Transactional public void joinV3(String username) throws Exception { Member member = new Member(username); Log logMessage = new Log(username); log.info("== memberRepository 호출 시작 =="); memberRepository.save(member); log.info("== memberRepository 호출 종료 =="); log.info("== logRepository 호출 시작 =="); try { logRepository.saveV2(logMessage); } catch (Exception e) { log.info("log 로그 저장에 실패했습니다. logMessage={}", logMessage.getMessage()); logRepository.saveV2(new Log("체크예외발생!!")); log.info("joinV3: 체크 예외가 발생하였습니다!!!"); } log.info("== logRepository 호출 종료 =="); }체크예외를 던지는 logRepository.saveV2 내용@Transactional public void saveV2(Log logMessage) throws Exception { log.info("log 저장"); if (logMessage.getMessage().contains("로그예외")) { log.info("log 저장시 예외 발생"); throw new Exception("예외 발생"); } em.persist(logMessage); }회원가입요청 서비스를 테스트하는 코드 내용/** * MemberService @Transactional: ON * MemberRepository @Transactional: ON * LogRepository @Transactional Checked Exception */ @Test void recoverCheckedException_success() throws Exception { // given String username = "로그예외_outerTxOn_fail"; String errorUsername = "체크예외발생!!"; // when memberService.joinV3(username); // then: member 저장, log 오류내용 저장 assertTrue(memberRepository.find(username).isPresent()); assertTrue(logRepository.find(errorUsername).isPresent()); }