@Transactional을 사용하면 스프링의 트랜잭션 AOP가 적용된다.
이는 프록시 방식의 AOP를 사용하는데, 프록시 객체를 스프링 빈으로 주입받아 메서드가 실행되면, 적용 대상인지 아닌지를 프록시 객체가 판단 후에 실제 객체의 메서드를 호출하는 것이다.
만약 대상 객체를 직접 호출하게 되면 AOP가 적용되지 않고, 트랜잭션도 적용되지 않는다.
대상 객체 내부에서 메서드 호출이 발생할 경우, 프록시를 거치지 않고 대상 객체를 직접 호출하는 문제가 발생 할 수 있다.
이 경우 @Transactional이 있어도 트랜잭션이 적용되지 않는다.
InternalCallV1Test
@Slf4j
@SpringBootTest
public class InternalCallV1Test {
@Autowired CallService callService;
@Test
void printProxy() {
log.info("callService class={}",callService.getClass());
}
@Test
void internalCall() {
callService.internal(); }
@Test
void externalCall() {
callService.external(); }
@TestConfiguration
static class InternalCallV1TestConfig {
@Bean
CallService callService() {
return new CallService();}
}
@Slf4j
static class CallService {
public void external() {
log.info("call external");
printTxInfo();
internal();
}
@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에서 external 메서드는 트랜잭션을 선언하지 않았고, internal()은 트랜잭션을 선언했다.
따라서 external 메서드를 실행할 경우, 트랜잭션이 시작하지 않을 것이고, 내부에서 트랜잭션을 선언했던 internal을 호출할 경우 어떻게 될까?
- internal() 메서드 실행
- external() 메서드 실행
예상과 다르게 external에서 트랜잭션을 선언했던 internal 메서드를 실행했음에도 불구하고 트랜잭션이 시작되지 않았다.
문제 원인
external 메서드가 실행되는 호출의 흐름은 아래와 같다.
- callService.external() 호출
- callService의 트랜잭션 프록시 호출
- external()은 트랜잭션 적용 대상이 아니므로 실제 객체의 external() 호출
- external() 내부에서 internal() 메서드 호출
자바에서는 메서드 앞에 참조 객체를 생략할 경우, this라는 뜻으로 자신의 인스턴스의 메서드를 호출한다.
자신의 인스턴스는 실제 객체이므로, 트랜잭션 프록시를 거치지 않아서 트랜잭션이 적용되지 않는 것이다.
이 문제를 해결하기 위해 internal() 메서드를 별도의 클래스로 분리해서 사용해야 한다.
출처
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] 트랜잭션 전파 - 1 (0) | 2023.02.05 |
---|---|
[Spring] 트랜잭션 - 프록시 내부 호출 문제 2 (0) | 2023.02.03 |
[Spring] 선언적 트랜잭션 동작 확인하기 (0) | 2023.02.03 |
[Spring DB] MyBatis 사용하기 (0) | 2023.01.29 |
[Spring DB] 테스트 - 트랜잭션 (0) | 2023.01.29 |