인프런 커뮤니티 질문&답변

위진님의 프로필 이미지

작성한 질문수

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

트랜잭션 AOP 주의 사항 - 프록시 내부 호출1

REQUIRES_NEW와 내부 호출

24.08.22 16:50 작성

·

29

0

[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예

[질문 내용]

내부 호출 문제점은 REQUIRES_NEW 어노테이션이 적용된 경우에도 동일하게 발생하는 것 같은데 맞을까요??

 

아래 코드를 실행했을 때 커밋이 한 번도 발생하지 않는 것을 로그로 확인했습니다.

 

혹시나 해서 여쭤봅니다!!

 

@Slf4j
@SpringBootTest
public class InternalCallV1Test {

    @Autowired
    CallService callService;
    
    @Test
    void externalCall() {
        callService.external();
    }

    @TestConfiguration
    static class InternalCallV1TestConfig {
        @Bean
        CallService callService() {
            return new CallService();
        }
    }

    @Slf4j
    static class CallService {

        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void internal() {
            log.info("call internal");
            printTxInfo();
        }

        @Transactional
        public void external() {
            log.info("call external");
            printTxInfo();
            this.internal();
            throw new RuntimeException("종료");
        }

        private void printTxInfo() {
            boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
            log.info("tx active={}", txActive);
        }
    }
}

답변 1

0

인프런 AI 인턴님의 프로필 이미지

2024. 08. 22. 16:56

안녕하세요, 인프런 AI 인턴입니다.

위진님께서 제시하신 코드와 관련된, REQUIRES_NEW 어노테이션과 내부 호출에 대한 문제 상황에 대해 질문하셨군요. 살펴보니 이와 유사한 주제를 다룬 기존의 논의를 찾았습니다. 본질적으로, REQUIRES_NEW 어노테이션이 적용된 메서드를 내부에서 호출할 때 해당 어노테이션이 기대하는 동작(새로운 트랜잭션 시작)이 제대로 작동하지 않는 경우가 일반적이라는 점에 집중할 필요가 있습니다.

프록시 호출과 관련된 질문에서, @Transactional이 적용된 메서드를 같은 클래스 내 다른 메서드에서 직접 호출하는 경우(Spring AOP Proxy를 통하지 않고 직접적인 Java 메서드 호출을 통해), 트랜잭션 어드바이스가 적용되지 않습니다. 이로 인해, REQUIRES_NEW와 같이 특정 트랜잭션 전파 동작을 기대했더라도 실제로는 원하는 동작이 이루어지지 않는 문제가 발생합니다. 이런 경우, REQUIRES_NEW가 예상대로 작동하지 않아 트랜잭션이 새롭게 시작되지 않으며, 결과적으로 외부 메서드(external)에 의해 시작된 트랜잭션만이 적용됩니다.

따라서 질문하신 상황에서 REQUIRES_NEW 어노테이션이 적용된 internal 메서드를 external 메서드 내부에서 직접 호출하더라도, internal 메서드에 기대했던 새로운 트랜잭션이 시작되지 않는 것은 Spring AOP의 프록시 기반 동작 방식으로 인한 것으로 보입니다. internal 메서드가 프록시를 통해 호출되어야만 새로운 트랜잭션이 시작되는데, 이 예제에서는 this.internal() 호출이 Java의 일반 메서드 호출로 처리되어 프록시를 통한 트랜잭션 처리가 이루어지지 않는 것입니다.

이 문제를 해결하기 위한 접근법 중 하나로, 자기 자신을 주입받는 방식(self-injection)을 사용하여 내부 호출이 프록시를 통해 이루어지도록 할 수 있지만, 이는 권장되는 방법은 아닙니다. 좀 더 일반적인 해결책으로는, 트랜잭션이 필요한 로직을 외부 서비스로 분리하여 각각의 메서드가 독립적으로 프록시를 통해 호출될 수 있도록 조정하는 것입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

위진님의 프로필 이미지

작성한 질문수

질문하기