///////
Search
🍏

@Transactional를 스프링 Bean 메서드 A에 적용하였고, 해당 Bean의 메서드 B가 호출되었을 때 메서드 내부에서 메서드 A를 호출하면 어떤 요청 흐름이 발생하게 되나요?

요약

프록시는 클라이언트가 타겟 객체를 호출하는 과정에만 동작하며, 타겟 객체의 메소드가 자기 자신의 다른 메소드를 호출할 때는 프록시가 동작하지 않는다. A 메소드는 프록시로 감싸진 메소드가 아니므로 트랜잭션이 적용되지 않는 일반 코드가 수행된다.

예시

static class CallService{ public void external() { printTxInfo(); internal(); } @Transactional public void internal() { printTxInfo(); } private void printTxInfo() { boolean txActive = TransactionSynchronizationManager.isActualTransactionActive(); log.info("tx Active={}", txActive); } }
Java
복사
1.
클라이언트인 테스트 코드가 callService.external() 을 호출
2.
callService 의 트랜잭션 프록시가 호출
3.
external() 에는 @Transactional 이 없으므로 프록시는 트랜잭션을 적용하지 않는다
4.
트랜잭션을 적용하지 않고 실제 callService 의 external() 를 호출
5.
external() 은 내부에서 internal() 메서드를 호출하는데 여기서 문제가 발생
실제 대상 객체 내부에서 호출하기 때문에 this.internal() 이 되어버린다
프록시를 거치지 않고 실제 대상 객체( this )의 메서드를 호출하기 때문에 트랜잭션을 적용할 수 없다

해결 방법

internal() 메서드를 별도의 클래스로 분리
static class CallService{ private final InternalService internalService; public void external() { printTxInfo(); internalService.internal(); } } static class InternalService { @Transactional public void internal() { printTxInfo(); } }
Java
복사