만약, 멤버 클래스와 팀 클래스가 연관관계로 매핑되어 있다고 가정하자.
이때, 조회는 아래와 같이 3가지의 경우의 수가 있다.
- 멤버만 조회
- 팀만 조회
- 멤버와 팀 모두 조회
하지만, 팀과 멤버는 연관관계 매핑이 되어있어, 우리는 멤버 혹은 팀 하나만 조회하고 싶은데, 항상 한번에 양 쪽을 모두 select 쿼리를 날려 가져온다.
//1. member 생성 후, 저장
Team team = new Team();
Member member = new Mmeber();
member.setName("son");
member.setTeam(team);
em.persist(member);
em.flush();
em.clear();
//2. member만 조회
Member member = em.find(Member.class, 1L);
//3. 하지만, Team까지 같이 가져와버려, 팀도 조회가 된다...!
Team team = member.getTeam();
이러한 문제를 JPA는 지연로딩과 즉시로딩으로 해결한다.
지연로딩과 즉시로딩을 이해하기 위해서는 먼저, 프록시에 대해서 이해를 해야한다.
프록시에 대해
프록시 = 임시 참조 객체. 초기에는 빈 껍데기만 있는 객체이고, 실제 사용 시, 프록시 객체 안에 실제 DB의 값들이 채워진다. (type은 변하지 않음!)
JPA에서는 조회에 대해 2개의 함수가 있다.
1. em.find()
2. em.getRefenrence()
- em.find()
- DB에서 실제 엔티티 객체를 조회해 가져온다.
- 조회 시점에 바로 Select 쿼리가 날라감.
- em.getReference()
- DB 조회를 미루는 가짜(프록시) 엔티티 객체를 조회해 가져온다.
- 조회할 때 Select 쿼리가 안날라가고, 실제 데이터를 사용할 때, 쿼리가 날라감.
//이때, 조회(Select) 쿼리문이 바로 날라감.
//member는 실제 Entity 객체
Member member = em.find(Member.class, 1L);
//select 쿼리문 안날라감
//member는 가짜 프록시 객체
Member member = em.getReference(Member.class, 1L);
//이때, 쿼리문 날라감
//이렇게, 데이터 직접 사용으로 인해 조회가 필요할 때, 쿼리문이 날라간다.
//이때, member는 실제 Entity 객체가 된다.
System.out.println(member.getName);
- JPA는 항상 프록시와 실제 객체의 "==" 비교를 True로 보장해준다.
mem1 = em.getReference(Member.class, 1L); //프록시 객체 반환
mem2 = em.find(Member.class, 1L); // mem1과의 "=="비교를 보장해주기 위해 프록시 객체 반환
sout(mem1 == mem2) // True 반환...
- 준영속 상태에서 프록시 초기화 ➡️ Error
Member member = em.getReference(Member.class, 1L);
em.detach(member);
//or em.close();
//에러 발생, 영속성 컨텍스트 내 member가 준영속 상태 or 영속성 컨텍스트가 닫혀 프록시 객체를 초기화할 수 없다.
member.getName();
'JPA' 카테고리의 다른 글
조건식 (case, coalesce, nullif) (0) | 2023.05.29 |
---|---|
즉시로딩(EAGER Loading)과 지연로딩(LAZY LOADING) (0) | 2023.05.23 |
JPA - 연관관계 주인(feat. mappedBy) (0) | 2023.05.19 |
영속성 컨텍스트! (2) | 2023.05.11 |
자바의 트랜잭션 (0) | 2023.05.09 |