• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    해결됨

@Transactional 과 entityManager 범위에 관해 질문 드립니다.

24.01.02 23:07 작성 24.01.03 02:53 수정 조회수 313

0

안녕하세요! 강의 수강 중 질문이 생겨 작성합니다.. 답변 부탁드립니다..!ㅠ.ㅠ

 

-- MemberRepository 입니다. ( @Transactional 키워드 모두 지움 )

@Repository
public class MemberRepository {

    @PersistenceContext
    EntityManager em;

 
    public Member findMember( Long id ) {
        Member member = em.find(Member.class, id);
        return member;
    }

    public Member findMember2( Long id ) {
        Member member = em.find(Member.class, id);
        return member;
    }
}

 

-- 위 레파지토리를 호출하는 테스트 코드 입니다. ( 데이터는 미리 넣어둔 상태 입니다. )

@SpringBootTest
class MemberRepositoryTest {

    @Autowired MemberRepository mRepo;

    @Test
    public void test2() {
        System.out.println("=================================================");
        System.out.println(mRepo.getClass());

        //when
        Member found1 = mRepo.findMember(1L);
        Member found2 = mRepo.findMember2(1L);

        System.out.println("=================================================");
        //then
        assertEquals(found2, found1);
    }
}

 

 

1 ) 테스트 코드에서 주입받은 mRepo의 클래스 타입을 확인하면 CGLIB로 생성한 프록시 클래스가 출력됩니다.

위 코드에서 보는 바와 같이 @Transactional 어노테이션은 존재하지 않는데도 실 클래스가 아닌 프록시 객체로 만들어지는 이유가 뭔가요??

 

2 ) 테스트 코드에서 test2()를 실행하면 select를 2번 실행합니다.

test2()에 @Transactional을 걸면 -> select 1번 -> 너무 당연한데

MemberRepo 클래스 레벨에서 @Transactional -> 테스트 코드 실행 시 select 2번

MemberRepo 클래스 각 메소드에 @Transactional -> 테스트 코드 실행 시 select 2번

 

2-1) 위와 같은 결과가 발생하는 이유를 모르겠습니다.. @Transactional을 어떻게 걸든 한 메소드가 종료하고 나면 PersistenceContext 가 닫히는 건가요?..

 

2-2) MemberRepo 에서 주입받은 entityManager는 proxy 클래스가 맞는거죠..?

@Transactional을 표기해주지 않아도, em을 사용하는 메소드가 호출되고 종료 될 때마다, 매번 proxy 객체 내부의 실제 entityManager 객체가 변경되는 건가요??

 

2-3) em.find(Member.class, 1L) 같은 조회성 질의에서

@Transactional(readOnly=true) 와 아예 해당 어노테이션을 사용하지 않았을 경우의 결과가 동일하였습니다. 그렇다면 readOnly를 사용하는 이유가 대체 무엇인가요?..

 

질문이 많아서 죄송합니다 ㅠㅠ 머리에 정리가 되질 않아서요..답변 부탁드립니다!!

답변 2

·

답변을 작성해보세요.

1

y2gcoder님의 프로필

y2gcoder

2024.01.03

안녕하세요. qpal1zm23님, 공식 서포터즈 y2gcoder입니다.

1) MemberRepository 가 프록시로 등록되는 원인은 @Transactional 에만 있지 않습니다. 스프링 AOP 나 다른 스프링 설정에 의해서도 프록시를 생성할 수 있기 때문에, 이 부분에 대해서는 어떤 것이 원인이라고 딱 답을 드리기 어려울 것 같습니다 ㅜㅜ

2, 2-1) 트랜잭션 단위로 영속성 컨텍스트가 살아있기 때문입니다. test2()에 트랜잭션을 걸었을 때는 해당 테스트 메서드가 끝날 때까지 모두 한 트랜잭션 내에 있기 때문에 findMember, findMember2 모두 하나의 영속성 컨텍스트를 공유합니다. 반면에 말씀해주신 MemberRepository의 클래스 레벨이나 메서드 레벨에 @Transactional을 걸어줬을 때는 각각 메서드 레벨에 트랜잭션이 걸리게 됩니다. 즉 findMember() 와 findMember2() 범위에서 트랜잭션이 작동합니다! 그러면 테스트 코드에서는 당연히 findMember(), findMember2() 각 범위에서 다른 트랜잭션이 작동하기 때문에 서로 다른 영속성 컨텍스트고, 따라서 조회 쿼리가 2개 날아가게 되는 것입니다 🙂 해당 부분은 영속성 컨텍스트 관련해서는 영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 강의와 트랜잭션 관련해서는 영한님의 스프링 DB 2편 - 데이터 접근 활용 기술 강의를 참고해주십쇼!

2-2) 맞습니다. 이 부분에 대해서는 다음 링크(클릭)을 참고해주십쇼!

2-3) 이 부분은 다음 링크(클릭) 에서 잘 정리하고 있다고 생각합니다. 참고해주십쇼!

 

감사합니다.

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2024.01.02

안녕하세요, 인프런 AI 인턴입니다.

질문하신 내용과 관련된 김영한 강사님의 답변이 있는 게시글을 찾았습니다. 아래 링크를 참고하시면 EntityManager, @Transactional 어노테이션의 동작 방식 및 범위에 대한 이해에 도움이 될 것입니다.

강사님께서 자세하게 답변해 주신 내용을 확인하시고, 추가로 궁금한 점이 있다면 해당 게시물에 질문을 남기시면 됩니다.

도움이 되셨길 바랍니다.