[Spring] 스프링 DB 2편 11-2. 트랜잭션 전파 활용2 - 커밋, 롤백

강우엉·2023년 9월 4일

Spring

목록 보기
351/359

서비스 계층에 트랜잭션이 없을 때 - 커밋
예제를 통해 서비스 계층에 트랜잭션이 없을 때 트랜잭션이 각각 어떻게 작동하는지 확인해보자.

상황
서비스 계층에 트랜잭션이 없다.
회원, 로그 리포지토리가 각각 트랜잭션을 가지고 있다.
회원, 로그 리포지토리 둘다 커밋에 성공한다.

outerTxOff_success

 @Test
    void outerTxOff_success() {
        //given
        String username = "outerTxOff_success";

        //when
        memberService.joinV1(username);

        //then: 모든 데이터가 정상 저장된다.
        assertTrue(memberRepository.find(username).isPresent());
        assertTrue(logRepository.find(username).isPresent());
    }

    1. MemberService 에서 MemberRepository 를 호출한다. MemberRepository 에는 @Transactional 애노테이션이 있으므로 트랜잭션 AOP가 작동한다. 여기서 트랜잭션 매니저를 통해 트랜잭션을 시작한다. 이렇게 시작한 트랜잭션을 트랜잭션B라 하자.
    • 그림에서는 생략했지만, 트랜잭션 매니저에 트랜잭션을 요청하면 데이터소스를 통해 커넥션 con1 을 획득하고, 해당 커넥션을 수동 커밋 모드로 변경해서 트랜잭션을 시작한다.
    • 그리고 트랜잭션 동기화 매니저를 통해 트랜잭션을 시작한 커넥션을 보관한다.
    • 트랜잭션 매니저의 호출 결과로 status 를 반환한다. 여기서는 신규 트랜잭션 여부가 참이 된다.
    1. MemberRepository 는 JPA를 통해 회원을 저장하는데, 이때 JPA는 트랜잭션이 시작된 con1 을 사용해서 회원을 저장한다.
    1. MemberRepository 가 정상 응답을 반환했기 때문에 트랜잭션 AOP는 트랜잭션 매니저에 커밋을 요청한다.
    1. 트랜잭션 매니저는 con1 을 통해 물리 트랜잭션을 커밋한다.
    • 물론 이 시점에 앞서 설명한 신규 트랜잭션 여부, rollbackOnly 여부를 모두 체크한다.

이렇게 해서 MemberRepository 와 관련된 모든 데이터는 정상 커밋되고, 트랜잭션B는 완전히 종료된다. 이후에 LogRepository 를 통해 트랜잭션C를 시작하고, 정상 커밋한다.
결과적으로 둘다 커밋되었으므로 Member , Log 모두 안전하게 저장된다.

서비스 계층에 트랜잭션이 없을 때 - 롤백
상황

서비스 계층에 트랜잭션이 없다.
회원, 로그 리포지토리가 각각 트랜잭션을 가지고 있다.
회원 리포지토리는 정상 동작하지만 로그 리포지토리에서 예외가 발생한다.

outerTxOff_fail

@Test
    void outerTxOff_fail() {
        //given
        String username = "로그예외_outerTxOff_fail";

        //when
        assertThatThrownBy(() -> memberService.joinV1(username))
                .isInstanceOf(RuntimeException.class);

        //then: 모든 데이터가 정상 저장된다.
        assertTrue(memberRepository.find(username).isPresent());
        assertTrue(logRepository.find(username).isEmpty());
    }
  • 사용자 이름에 로그예외 라는 단어가 포함되어 있으면 LogRepository 에서 런타임 예외가 발생한다.
  • 트랜잭션 AOP는 해당 런타임 예외를 확인하고 롤백 처리한다.


  • MemberService 에서 MemberRepository 를 호출하는 부분은 앞서 설명한 내용과 같다. 트랜잭션이 정상 커밋되고, 회원 데이터도 DB에 정상 반영된다.
  • MemberService 에서 LogRepository 를 호출하는데, 로그예외 라는 이름을 전달한다. 이 과정에서 새로운 트랜잭션 C가 만들어진다.

LogRepository 응답 로직
1. LogRepository 는 트랜잭션C와 관련된 con2 를 사용한다.
2. 로그예외 라는 이름을 전달해서 LogRepository 에 런타임 예외가 발생한다.
3. LogRepository 는 해당 예외를 밖으로 던진다. 이 경우 트랜잭션 AOP가 예외를 받게된다.
4. 런타임 예외가 발생해서 트랜잭션 AOP는 트랜잭션 매니저에 롤백을 호출한다.
5. 트랜잭션 매니저는 신규 트랜잭션이므로 물리 롤백을 호출한다.

profile
우엉이의 코딩 성장일기💻

0개의 댓글