728x90
서비스 계층에 트랜잭션이 없을 때 - 커밋
/**
* memberService @Transactional:OFF
* memberRepository @Transactional:ON
* logRepository @Transactional:ON
*/
@Test
public void outerTxOff_success() {
//given
String username = "outerTxOff_success";
//when
memberService.joinV1(username);
//then : 모든 데이터가 정상 저장된다.
assertTrue(memberRepository.find(username).isPresent());
assertTrue(logRepository.find(username).isPresent());
}

- MemberService에서 MemberRepository를 호출한다. MemberRepository 에는 @Transactional 애노테이션이 있으므로 트랜잭션 AOP가 작동한다. 여기서 트랜잭션 매니저를 통해 트랜잭션을 시작한다. 이렇게 시작한 트랜잭션을 트랜잭션 B라 하자.
- 그림에서는 생략했지만, 트랜잭션 매니저에 트랜잭션을 요청하면 데이터소스를 통해 커넥션 con1을 획득하고, 해당 커넥션을 수동 커밋 모드로 변경해서 트랜잭션을 시작한다.
- 그리고 트랜잭션 동기화 매니저를 통해 트랜잭션을 시작한 커넥션을 보관한다.
- 트랜잭션 매니저의 호출 결과로 status 를 반환한다. 여기서는 신규 트랜잭션 여부가 참이 된다.
- MemberRepository 는 JPA를 통해 회원을 저장하는데, 이때 JPA는 트랜잭션이 시작된 con1을 사용해서 회원을 저장한다.
- MemberRepository 가 정상 응답을 반환했기 때문에 트랜잭션 AOP는 트랜잭션 매니저에 커밋을 요청한다.
- 트랜잭션 매니저는 con1 을 통해 물리 트랜잭션을 커밋한다.
- 물론 이 시점에 앞서 설명한 신규 트랜잭션 여부, rollbackOnly 여부를 모두 체크한다.
이렇게 해서 MemberRepository 와 관련된 모든 데이터는 정상 커밋되고, 트랜잭션 B는 완전히 종료된다. 이후에 LogRepository를 통해 트랜잭션 C를 시작하고, 정상 커밋한다. 결과적으로 둘 다 커밋되었으므로 Member , Log 모두 안전하게 저장된다.
@Transactional과 REQUIRED
트랜잭션 전파의 기본 값은 REQUIRED 이다. 따라서 다음 둘은 같다.
- @Transactional(propagation = Propagation.REQUIRED)
- @Transactional
REQUIRED 는 기존 트랜잭션이 없으면 새로운 트랜잭션을 만들고, 기존 트랜잭션이 있으면 참여한다.
서비스 계층에 트랜잭션이 없을 때 - 롤백
/**
* memberService @Transactional:OFF
* memberRepository @Transactional:ON
* logRepository @Transactional:ON Exception
*/
@Test
public 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 응답 로직
- LogRepository 는 트랜잭션 C와 관련된 con2를 사용한다.
- 로그예외 라는 이름을 전달해서 LogRepository에 런타임 예외가 발생한다.
- LogRepository 는 해당 예외를 밖으로 던진다. 이 경우 트랜잭션 AOP가 예외를 받게 된다.
- 런타임 예외가 발생해서 트랜잭션 AOP는 트랜잭션 매니저에 롤백을 호출한다.
- 트랜잭션 매니저는 신규 트랜잭션이므로 물리 롤백을 호출한다
728x90
'스프링 DB 2편(데이터 접근 활용 기술)' 카테고리의 다른 글
| Ch11. 스프링 트랜잭션 전파(활용) - 전파 커밋 (0) | 2022.07.08 |
|---|---|
| Ch11. 스프링 트랜잭션 전파(활용) - 단일 트랜잭션 (0) | 2022.07.08 |
| Ch11. 스프링 트랜잭션 전파(활용) - 예제 프로젝트 시작 (0) | 2022.07.08 |
| Ch10. 스프링 트랜잭션 전파(기본) - 다양한 전파 옵션 (0) | 2022.07.08 |
| Ch10. 스프링 트랜잭션 전파(기본) - REQUIRES_NEW (0) | 2022.07.07 |