@Transactional 과 entityManager 범위에 관해 질문 드립니다.
안녕하세요! 강의 수강 중 질문이 생겨 작성합니다.. 답변 부탁드립니다..!ㅠ.ㅠ
-- 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 어노테이션의 동작 방식 및 범위에 대한 이해에 도움이 될 것입니다.
강사님께서 자세하게 답변해 주신 내용을 확인하시고, 추가로 궁금한 점이 있다면 해당 게시물에 질문을 남기시면 됩니다.
도움이 되셨길 바랍니다.
sdk 설정 오류
0
53
2
오탈자 - @Transactional
0
56
1
src/test/resources 테스트 경로 문제
0
50
1
상품 등록후 H2 db 출력 순서 바꿀 수 있나요?
0
64
1
MemberRepositoryTest 실행오류
0
81
1
boot 4.x >>> trasasction rolled back log & p6spy(영한님, 수업 자료 업데이트 해주시면 감사하겠습니다!!)
1
184
2
강의 마지막 QueryDSL 사용 부분 질문있습니다
1
142
2
클라이언트에서 isbn과 author 수정 요청을 한 경우에 대해 질문드립니다.
0
51
1
도메인 모델 패턴 vs 트랜잭션 스크립트 패턴
0
71
1
기본 생성자
0
60
1
h2 DB 연결시 jdbc url 변경 이유가 궁금합니다.
0
103
1
멤버서비스테스트 부분에서 막힙니다.
0
165
4
실무에서도 EntityManager를 이용해서 많이 작업하는 편일까요?
0
116
1
초반에 h2 다운로드 과정 꼭 필요한가요?
0
120
2
자신 필드에도 get으로 접근하는 이유가 있을까요?
0
114
1
24분 27초 연관관계 편의 메서드 위치
0
113
1
단건 주문만 가능하게 한건 의도한 부분이신가요?
0
109
2
빌드 툴, Gradle
0
59
1
h2연결은 된 것 같은데 엔티티 테이블까지 작성 후 확인해보아도 테이블이 안보입니다
0
77
2
Repository에서 EntityManager 주입 방식 차이
0
90
1
롬복과 사용자 정의 setter 메서드
0
73
1
주문 목록 조회 fetch join 질문드립니다
0
82
1
dirty checking 질문드립니다.
0
83
1
동시성 관련 질문입니다
0
75
1





