같은 클래스 안에서 호출한 @Transactional이 안 먹는 이유
조회 1 · 댓글 0
같은 서비스 클래스 안에서 @Transactional이 붙은 메서드를 다른 메서드가 this로 직접 호출하면 트랜잭션이 시작되지 않습니다. 로그를 봐도 트랜잭션이 안 열리는데 애노테이션은 분명히 붙어 있어서 헷갈리기 쉽습니다.
@Service
public class OrderService {
public void place() {
this.save(); // 프록시를 거치지 않음 -> 트랜잭션 안 열림
}
@Transactional
public void save() { ... }
}원인은 기본 proxy 모드에서는 프록시를 통해 들어오는 외부 호출만 가로채기 때문입니다. 공식 문서는 "self-invocation(대상 객체 안에서 자기 자신의 다른 메서드를 호출하는 것)은 호출된 메서드에 @Transactional이 붙어 있어도 런타임에 실제 트랜잭션으로 이어지지 않는다"고 명시합니다. 내부 this 호출은 어드바이스를 우회한다는 설명도 같습니다. 같은 이유로 @Async, @Cacheable 같은 프록시 기반 기능도 내부 호출에서는 동작하지 않습니다.
해결은 트랜잭션 메서드를 별도 빈으로 분리해 주입받아 호출하거나, 자기 자신을 프록시로 주입받아 호출하는 방식입니다. 자기 호출까지 감싸야 한다면 프록시 대신 mode=aspectj 위빙을 쓸 수 있습니다. 참고로 가시성은 보통 public이며, 6.0부터 클래스 기반 프록시는 protected와 package 범위 메서드도 트랜잭션 대상이 되지만 인터페이스 기반 프록시는 프록시 대상 인터페이스에 정의된 public 메서드여야 합니다.
🔗 https://docs.spring.io/spring-framework/reference/core/aop/proxying.html
로그인 후 답글을 남길 수 있습니다.