요약
프록시는 클라이언트가 타겟 객체를 호출하는 과정에만 동작하며, 타겟 객체의 메소드가 자기 자신의 다른 메소드를 호출할 때는 프록시가 동작하지 않는다. 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
복사