분류 전체보기 1341

Ch11. 스프링 트랜잭션 전파(활용) - 전파 커밋

스프링은 @Transactional 이 적용되어 있으면 기본으로 REQUIRED라는 전파 옵션을 사용한다. 이 옵션은 기존 트랜잭션이 없으면 트랜잭션을 생성하고, 기존 트랜잭션이 있으면 기존 트랜잭션에 참여한다. 참여한다는 뜻은 해당 트랜잭션을 그대로 따른다는 뜻이고, 동시에 같은 동기화 커넥션을 사용한다는 뜻이다 이 경우 외부에 있는 신규 트랜잭션만 실제 물리 트랜잭션을 시작하고 커밋한다. 내부에 있는 트랜잭션은 물리 트랜잭션 시작하거나 커밋하지 않는다.3 /** * memberService @Transactional:ON * memberRepository @Transactional:ON * logRepository @Transactional:ON */ @Test public void outerTxOn..

Ch11. 스프링 트랜잭션 전파(활용) - 단일 트랜잭션

회원 리포지토리와 로그 리포지토리를 하나의 트랜잭션으로 묶는 가장 간단한 방법은 이 둘을 호출하는 회원 서비스에만 트랜잭션을 사용하는 것이다 /** * memberService @Transactional:ON * memberRepository @Transactional:OFF * logRepository @Transactional:OFF */ @Test public void singleTx() { //given String username = "outerTxOff_success"; //when memberService.joinV1(username); //then : 모든 데이터가 정상 저장된다. assertTrue(memberRepository.find(username).isPresent()); asse..

Ch11. 스프링 트랜잭션 전파(활용) - 서비스 계층에 트랜잭션이 없을 때 (커밋, 롤백)

서비스 계층에 트랜잭션이 없을 때 - 커밋 /** * 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(..

Ch11. 스프링 트랜잭션 전파(활용) - 예제 프로젝트 시작

Member @Entity @Getter @Setter public class Member { @Id @GeneratedValue private Long id; private String username; public Member(){ } public Member(String username) { this.username = username; } } MemberRepository @Slf4j @Repository @RequiredArgsConstructor public class MemberRepository { private final EntityManager em; @Transactional public void save(Member member){ log.info("member 저장"); em.pe..

Ch10. 스프링 트랜잭션 전파(기본) - 다양한 전파 옵션

스프링은 다양한 트랜잭션 전파 옵션을 제공한다. 전파 옵션에 별도의 설정을 하지 않으면 REQUIRED 가 기본으로 사용된다. 참고로 실무에서는 대부분 REQUIRED 옵션을 사용한다. 그리고 아주 가끔 REQUIRES_NEW을 사용하고, 나머지는 거의 사용하지 않는다. 그래서 나머지 옵션은 이런 것이 있다는 정도로만 알아두고 필요할 때 찾아보자 REQUIRED 가장 많이 사용하는 기본 설정이다. 기존 트랜잭션이 없으면 생성하고, 있으면 참여한다. 트랜잭션이 필수라는 의미로 이해하면 된다. (필수이기 때문에 없으면 만들고, 있으면 참여한다.) 기존 트랜잭션 없음: 새로운 트랜잭션을 생성한다. 기존 트랜잭션 있음: 기존 트랜잭션에 참여한다 REQUIRES_NEW 항상 새로운 트랜잭션을 생성한다. 기존 트랜..

Ch10. 스프링 트랜잭션 전파(기본) - REQUIRES_NEW

외부 트랜잭션과 내부 트랜잭션을 완전히 분리해서 각각 별도의 물리 트랜잭션을 사용하는 방법이다. 그래서 커밋과 롤백도 각각 별도로 이루어지게 된다. 이 방법은 내부 트랜잭션에 문제가 발생해서 롤백해도, 외부 트랜잭션에는 영향을 주지 않는다. 반대로 외부 트랜잭션에 문제가 발생해도 내부 트랜잭션에 영향을 주지 않는다. 이 방법을 사용하는 구체적인 예는 이후에 알아보고 지금은 작동 원리를 이해해보자 이렇게 물리 트랜잭션을 분리하려면 내부 트랜잭션을 시작할 때 REQUIRES_NEW 옵션을 사용하면 된다. 외부 트랜잭션과 내부 트랜잭션이 각각 별도의 물리 트랜잭션을 가진다. 별도의 물리 트랜잭션을 가진다는 뜻은 DB 커넥션을 따로 사용한다는 뜻이다. 이 경우 내부 트랜잭션이 롤백되면서 로직 2가 롤백되어도 로..

Ch10. 스프링 트랜잭션 전파(기본) - 내부 롤백

@Test public void inner_rollback(){ log.info("외부 트랜잭션 시작"); TransactionStatus outer = txManager.getTransaction(new DefaultTransactionAttribute()); log.info("내부 트랜잭션 시작"); TransactionStatus inner = txManager.getTransaction(new DefaultTransactionAttribute()); log.info("내부 트랜잭션 롤백"); txManager.rollback(inner); //rollback-only 표시 log.info("외부 트랜잭션 커밋"); Assertions.assertThatThrownBy(() -> txManager...

Ch10. 스프링 트랜잭션 전파(기본) - 외부 롤백

@Test public void outer_rollback(){ log.info("외부 트랜잭션 시작"); TransactionStatus outer = txManager.getTransaction(new DefaultTransactionAttribute()); log.info("내부 트랜잭션 시작"); TransactionStatus inner = txManager.getTransaction(new DefaultTransactionAttribute()); log.info("내부 트랜잭션 커밋"); txManager.commit(inner); log.info("외부 트랜잭션 커밋"); txManager.rollback(outer); } 실행 결과 - outer_rollback() : 외부 트랜잭션 시작 ..

Ch10. 스프링 트랜잭션 전파(기본) - 전파 기본 & 예제

전파 기본 트랜잭션을 각각 사용하는 것이 아니라, 트랜잭션이 이미 진행 중인데, 여기에 추가로 트랜잭션을 수행하면 어떻게 될까? 기존 트랜잭션과 별도의 트랜잭션을 진행해야 할까? 아니면 기존 트랜잭션을 그대로 이어받아서 트랜잭션을 수행해야 할까? 이런 경우 어떻게 동작할지 결정하는 것을 트랜잭션 전파(propagation)라 한다. 참고로 스프링은 다양한 트랜잭션 전파 옵션을 제공한다. 지금부터 설명하는 내용은 트랜잭션 전파의 기본 옵션인 REQUIRED를 기준으로 설명한다. 옵션에 대한 내용은 마지막에 설명한다. 뒤에서 설명할 것이므로 참고만 해두자. 외부 트랜잭션이 수행중인데, 내부 트랜잭션이 추가로 수행됨 외부 트랜잭션이 수행중이고, 아직 끝나지 않았는데, 내부 트랜잭션이 수행된다. 외부 트랜잭션이..

Ch10. 스프링 트랜잭션 전파(기본) - 트랜잭션 두 번 사용

double_commit() @Test public void double_commit(){ log.info("트랜잭션1 시작"); TransactionStatus tx1 = txManager.getTransaction(new DefaultTransactionAttribute()); log.info("트랜잭션1 커밋"); txManager.commit(tx1); log.info("트랜잭션2 시작"); TransactionStatus tx2 = txManager.getTransaction(new DefaultTransactionAttribute()); log.info("트랜잭션2 커밋"); txManager.commit(tx2); } 트랜잭션 1 Acquired Connection [HikariProxyCo..