해결된 질문
작성
·
433
·
수정됨
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
안녕하세요. 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 인턴입니다.
질문하신 내용과 관련된 김영한 강사님의 답변이 있는 게시글을 찾았습니다. 아래 링크를 참고하시면 EntityManager, @Transactional 어노테이션의 동작 방식 및 범위에 대한 이해에 도움이 될 것입니다.
강사님께서 자세하게 답변해 주신 내용을 확인하시고, 추가로 궁금한 점이 있다면 해당 게시물에 질문을 남기시면 됩니다.
도움이 되셨길 바랍니다.