@Transactional이 붙지 않은 메서드 내부에서 @Transactional이 붙은 메서드를 호출할 경우, 트랜잭션이 적용되지 않는 문제가 생겼다.
메서드 내부에서의 다른 메서드의 호출은 this가 생략된, 즉 자기 자신의 인스턴스 객체의 메서드를 호출하는 것이기 때문에 프록시 객체를 거치지 않아 트랜잭션이 실행되지 않는다.
이를 해결하기 위해서 internal() 메서드를 별도의 클래스에서 실행해야한다.
InternalService
static class InternalService {
@Transactional
public void internal() {
log.info("call internal");
printTxInfo();
}
private void printTxInfo() {
boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
log.info("tx active={}",txActive);
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
log.info("tx readOnly={}",readOnly);
}
}
기존의 CallService의 internal 메서드를 별도의 InternalService를 생성해서 옮겨주었다.
CallService의 external 메서드를 실행할 때 숨겨진 참조때문에 트랜잭션이 발생하지 않았지만, 이제 CallService에서 InternalService를 주입받아 internal 메서드를 실행하면 된다.
수정한 CallService
@Slf4j
@RequiredArgsConstructor
static class CallService {
private final InternalService internalService;
public void external() {
log.info("call external");
printTxInfo();
internalService.internal(); //this 참조가 아닌 interService의 메서드로 변경
}
private void printTxInfo() {
boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
log.info("tx active={}",txActive);
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
log.info("tx readOnly={}",readOnly);
}
}
InternalService 내에 internal() 메서드는 @Transactional을 선언했기 때문에, CallService 내의 InternalService는 프록시 객체이다.
결과를 확인해보면

internal이 실행될때 트랜잭션이 시작됨을 알 수 있다.
정리해보면,
- 선언적 트랜잭션을 이용하는 메서드를 실행할때, 그 클래스는 프록시 AOP를 이용하여 프록시 객체를 주입받게 된다.
- 해당 메서드가 실행될 때, 프록시 객체가 메서드가 트랜잭션 대상인지 아닌지를 확인한 다음 실제 객체의 메서드를 실행한다.
- 이 때, 트랜잭션이 아닌 메서드를 실행하면 실제 객체의 메서드를 호출하는데, 이 때 그 메서드 내부에서 선언적 트랜잭션을 이용하는 메서드를 호출할 경우, 메서드의 참조(this)가 자기 자신의 인스턴스를 가리키므로 프록시 객체를 건너 띄고 내부 메서드를 호출하는 것이기 때문에 트랜잭션이 시작되지 않는다.
- 그래서 트랜잭션이 붙은 메서드를 내부에서 호출하고자 할 때에는 클래스를 따로 생성해서 사용해야한다.
출처
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard
스프링 DB 2편 - 데이터 접근 활용 기술 - 인프런 | 강의
백엔드 개발에 필요한 DB 데이터 접근 기술을 활용하고, 완성할 수 있습니다. 스프링 DB 접근 기술의 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., - 강의 소개 | 인
www.inflearn.com
'🍃Spring' 카테고리의 다른 글
| [Spring] 트랜잭션 전파 - 2 (0) | 2023.02.05 |
|---|---|
| [Spring] 트랜잭션 전파 - 1 (0) | 2023.02.05 |
| [Spring] 트랜잭션 - 프록시 내부 호출 문제 1 (0) | 2023.02.03 |
| [Spring] 선언적 트랜잭션 동작 확인하기 (0) | 2023.02.03 |
| [Spring DB] MyBatis 사용하기 (0) | 2023.01.29 |