waveofmymind
기록하는 습관
waveofmymind
전체 방문자
오늘
어제
  • 분류 전체보기 (124)
    • 📝 정리 (5)
    • 🌊TIL (9)
    • 💻CS (1)
      • 자료구조 (1)
    • 📙Language (9)
      • ☕Java (6)
      • 🤖Kotlin (3)
    • 🍃Spring (28)
    • 👨🏻‍💻알고리즘 (67)
      • 프로그래머스 (59)
      • 백준 (3)
    • 👷DevOps (4)
      • 🐳Docker (2)
      • 🤵Jenkins (1)

블로그 메뉴

  • 홈
  • Spring
  • Java
  • 알고리즘

공지사항

인기 글

태그

  • 완전탐색
  • til
  • kotest
  • 트랜잭션 전파
  • CORS
  • 다이나믹 프로그래밍
  • mybatis
  • 코틀린
  • kotlin
  • 챗GPT
  • 스프링
  • JDBC
  • LeetCode
  • Spring Security
  • 스프링 부트
  • Connection
  • 스택
  • 트랜잭션
  • sql
  • AOP
  • resultset
  • spring boot
  • SpringAOP
  • 힙
  • 스프링 시큐리티
  • spring
  • 통합테스트
  • BFS
  • chat GPT
  • Open AI

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
waveofmymind

기록하는 습관

[Spring] 트랜잭션 - 프록시 내부 호출 문제 2
🍃Spring

[Spring] 트랜잭션 - 프록시 내부 호출 문제 2

2023. 2. 3. 16:11

@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이 실행될때 트랜잭션이 시작됨을 알 수 있다.

 

정리해보면,

  1. 선언적 트랜잭션을 이용하는 메서드를 실행할때, 그 클래스는 프록시 AOP를 이용하여 프록시 객체를 주입받게 된다.
  2. 해당 메서드가 실행될 때, 프록시 객체가 메서드가 트랜잭션 대상인지 아닌지를 확인한 다음 실제 객체의 메서드를 실행한다.
  3. 이 때, 트랜잭션이 아닌 메서드를 실행하면 실제 객체의 메서드를 호출하는데, 이 때 그 메서드 내부에서 선언적 트랜잭션을 이용하는 메서드를 호출할 경우, 메서드의 참조(this)가 자기 자신의 인스턴스를 가리키므로 프록시 객체를 건너 띄고 내부 메서드를 호출하는 것이기 때문에 트랜잭션이 시작되지 않는다. 
  4. 그래서 트랜잭션이 붙은 메서드를 내부에서 호출하고자 할 때에는 클래스를 따로 생성해서 사용해야한다.

출처

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
    '🍃Spring' 카테고리의 다른 글
    • [Spring] 트랜잭션 전파 - 2
    • [Spring] 트랜잭션 전파 - 1
    • [Spring] 트랜잭션 - 프록시 내부 호출 문제 1
    • [Spring] 선언적 트랜잭션 동작 확인하기
    waveofmymind
    waveofmymind

    티스토리툴바