inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

스프링 DB 2편 - 데이터 접근 활용 기술

스프링 트랜잭션 전파 - REQUIRES_NEW 에 궁금한 점

831

gusdn85554

작성한 질문수 47

0

안녕하세요 영한님, 서포터즈님들

REQUIRES_NEW 옵션을 공부하면서 궁금한 점이 있습니다.

여기서 로직2의 트랜잭션 매니저에서는 내부 트랜잭션이므로 rollbackOnly 옵션을 확인하지 않는 것이 당연한 것으로 알고 있습니다.

그런데 외부, 내부 트랜잭션 구별 방법이 이전까지는 신규 트랜잭션인지 아닌지로 구별하였는데, REQUIRES_NEW 옵션에서는 외부,내부 트랜잭션을 구별하는 또 다른 옵션이 존재할까요,,?

제 생각에는 있을 것 같아서 내부 트랜잭션에서는 어떤 옵션이 있어서 rollbackonly 옵션을 확인하지 않을 것 같아서 질문 드립니다!!

키워드 알려주시면 찾아보겠습니다.

 

감사합니다.

spring

답변 2

0

y2gcoder

예제 프로젝트 (spring-tx)에서 추가해 실행해봤던 허접한 테스트입니다.

@Slf4j
@SpringBootTest
public class BasicTxTest {

	//...


	@Test
	void inner_inner_rollback() {
		log.info("외부 트랜잭션 시작");
		TransactionStatus outer = txManager.getTransaction(new DefaultTransactionAttribute());
		log.info("outer.isNewTransaction()={}", outer.isNewTransaction());  //true

		log.info("내부 트랜잭션 시작");
		TransactionStatus inner = txManager.getTransaction(new DefaultTransactionAttribute());
		log.info("inner.isNewTransaction()={}", inner.isNewTransaction());  //true



		log.info("내부-내부 트랜잭션 시작");
		TransactionStatus innerInner = txManager.getTransaction(new DefaultTransactionAttribute());
		log.info("innerInner.isNewTransaction()={}", innerInner.isNewTransaction());  //true
		log.info("내부-내부 트랜잭션 롤백");
		txManager.rollback(innerInner);  //rollback-only 표시

		log.info("내부 트랜잭션 커밋");
		txManager.commit(inner);

		log.info("외부 트랜잭션 커밋");
		assertThatThrownBy(() -> txManager.commit(outer))
				.isInstanceOf(UnexpectedRollbackException.class);
	}

	@Test
	void inner_inner_rollback_requires_new() {
		log.info("외부 트랜잭션 시작");
		TransactionStatus outer = txManager.getTransaction(new DefaultTransactionAttribute());
		log.info("outer.isNewTransaction()={}", outer.isNewTransaction());  //true

		log.info("내부 트랜잭션 시작");
		DefaultTransactionAttribute definition = new DefaultTransactionAttribute();
		definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
		TransactionStatus inner = txManager.getTransaction(definition);
		log.info("inner.isNewTransaction()={}", inner.isNewTransaction());  //true

		log.info("내부-내부 트랜잭션 시작");
		TransactionStatus innerInner = txManager.getTransaction(new DefaultTransactionAttribute());
		log.info("innerInner.isNewTransaction()={}", innerInner.isNewTransaction());  //true
		log.info("내부-내부 트랜잭션 롤백");
		txManager.rollback(innerInner);  //rollback-only 표시

		log.info("내부 트랜잭션 커밋");
		assertThatThrownBy(() -> txManager.commit(inner))
				.isInstanceOf(UnexpectedRollbackException.class);

		log.info("외부 트랜잭션 커밋");
		txManager.commit(outer);  //커밋
	}
}

 

먼저 inner_inner_rollback()의 로그입니다.

image

inner_inner_rollback_requires_new()의 로그입니다.

image 

 

0

y2gcoder

안녕하세요. gusdn85554님, 공식 서포터즈 y2gcoder입니다.

말씀해주신 부분을 듣고 생각해봤을 때 이제까지 외부 트랜잭션, 내부 트랜잭션을 나누고 외부와 내부 트랜잭션을 구분할 필요가 있었던 것은 단일 물리 트랜잭션 안에 새로운 논리 트랜잭션을 생성하여 기존 트랜잭션에 참여하는 방식이었기 때문이라고 생각합니다.

반면에 REQUIRES_NEW는 기존 트랜잭션에 참여하는 방식이 아니라, 또 다른 물리 트랜잭션을 만드는 것입니다. 별도의 두 물리 트랜잭션이 작동하는 방식이기 때문에 내부 트랜잭션에 문제가 생겨서 롤백해도, 외부 트랜잭션은 다른 물리 트랜잭션이기 때문에 사실 내부 트랜잭션의 결과가 어떻든 외부 트랜잭션에 영향을 주지 않습니다.

그런 맥락에서 위의 상황에서는 REQUIRED_NEW rollbackonly 옵션을 확인할 필요가 없습니다. 왜냐하면 외부 트랜잭션은 내부 트랜잭션의 결과에 영향을 받지 않는 별개의 물리 트랜잭션이기 때문입니다. rollbackonly라는 옵션은 하나의 물리 트랜잭션 안에 참여한 내부의 논리 트랜잭션이 있을 때, 체크할 필요가 있는 옵션이라고 생각합니다.


감사합니다.

0

gusdn85554

안녕하세요 y2gcoder님

REQUIRES_NEW로 생성된 내부 트랜잭션은 또 다른 물리 트랜잭션을 만드는 것이고, 해당 내부 트랜잭션에서는 또 다른 논리 트랜잭션이 존재하지 않기 때문에 rollbackOnly 옵션이 필요없다는 말씀으로 이해했습니다 !

여기서 궁금했던 점이 그림의 내부 트랜잭션 입장에서 '나는 내 안에 또 다른 트랜잭션을 가지고 있어' 라는 것을 알 수 있는 옵션이 따로 존재하는지 궁금해서요,,

 

감사합니다.

0

y2gcoder

REQUIRES_NEW로 생성된 내부 트랜잭션은 또 다른 물리 트랜잭션을 만드는 것이고, 해당 내부 트랜잭션에서는 또 다른 논리 트랜잭션이 존재하지 않기 때문에 rollbackOnly 옵션이 필요없다는 말씀으로 이해했습니다 ! 

rollbackOnly는 내부 논리 트랜잭션 에서 롤백이 발생해서 해당 물리 트랜잭션은 무조건 롤백해야 한다는 표시로 받아들이는 게 맞다고 생각합니다 :)

그리고 REQUIRES_NEW 옵션으로 생성된 트랜잭션은 새로운 연결을 사용한 물리 트랜잭션이니 내부에 논리 트랜잭션을 가질 수 있지 않을까 합니다.

저도 테스트와 디버깅을 찾아보면서 사실 질문자님께서 말씀해주셨던 외부 트랜잭션의 입장에서 자신이 내부 트랜잭션을 가지고 있는지에 대한 정보를 알 수 있는 방법은 찾지 못했습니다. 굳이 찾은 거라면 다른 물리 트랜잭션에 참여하게 된 논리 트랜잭션의 TransactionStatus의 속성 값 중 newTransaction의 속성값은 false라는 사실 뿐이었습니다. 실제로 newTransaction 속성은 문서에 따르면 해당 트랜잭션이 새로운지 여부를 반환하고, false라면 기존 트랜잭션에 참여하거나 실제 트랜잭션에서 실행되지 않았을 가능성이 있다고 합니다.

개인적으로 생각해본 것은 사실 외부 트랜잭션(=물리 트랜잭션)의 입장에서는 논리 트랜잭션이 실제로 커밋을 하는 것도 아니고, 그냥 자신의 트랜잭션을 갖다 쓰는 것이기 때문에 굳이 내부의 논리 트랜잭션을 알아야 하는가에 대한 생각도 들었습니다. 내부 트랜잭션에 대해 알아야 할 때는 내부 트랜잭션 로직에서 문제가 발생해 롤백이 필요할 때 뿐입니다. 그래서 롤백이 필요한 경우인지만 알기 위해 rollbackOnly 속성이 있는게 아닌가 하고 생각해봤습니다.

도움이 되지 못해 죄송합니다.

0

gusdn85554

아,, isNewTransaction() 이 있었네요,,감사합니다 y2gcoder님 !!

 

RepositoryTest의 패키지 위치가 domain인 이유

0

30

2

REQUIRES_NEW 해결 방법에 대해서 질문있습니다!!

0

30

1

update()에 사용하는 setter 질문드립니다.

0

47

1

SQL 중심적 개발의 문제점에 대한 질문

0

72

1

혹시 Containing 을 안쓰신 이유가 있을까요?

0

83

2

[공유] 스프링부트 4.x 버전 mybatis 연동

0

174

1

@repository 어노테이션

0

89

3

ItemService

0

58

1

논리 커밋, 물리 커밋 질문드립니다.

0

54

1

내부 트랜잭션 커밋은 필수인가요?

0

57

1

프록시 커넥션 객체를 반환할 때 생성하는건가요?

0

54

1

Transaction readOnly 성능 개선 (김영한님의 대한 감사인사)

2

178

2

JPQL 대신 네이티브 쿼리를 사용해야 하는 경우

0

77

1

@EventListener(ApplicationReadyEvent.class) 관련

0

88

1

트랜잭션 동기화 매니저와 데이터 소스

0

76

1

DB 관련 강의 개설 계획은 없으신건가요?

0

133

2

물리 트랜잭션 과 논리트랜잭션 용어를 맞게 이해한걸까요

0

94

1

스프링 3 버전 이상 rollbackFor 변경된듯요

1

112

1

트랜잭션 전파 질문.

0

87

1

프로젝트 오픈 에러

0

126

1

외부 트랜잭션에서 isNewTransaction이 false로 나오는거에 대해 질문드립니다

0

83

2

같은 스레드를 사용하면 트랜잭션 동기화 매니저는 같은 커넥션을 반환

0

72

1

h2 인메모리 테스트중 예약어 충돌날 경우 대처방법

0

102

1

커스텀aop와 트랜잭션을 같이 사용할때 우선순위에 관한 질문

0

98

2