BE전문가 프로젝트
즉시 로딩과 지연 로딩 본문
Member를 조회할 때 Team도 함께 조회해야 할까?
지연 로딩 LAZYY을 사용해서 프록시 조회
@Entity
public class Member extends BaseEntity{
@Id
@GeneratedValue
private Long id;
@Column(name="USERNAME")
private String username;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="TEAM_ID")
private Team team;
@OneToOne
@JoinColumn(name="LOCKER_ID")
private Locker locker;
}
FetchType.Lazy를 설정해준다면 해당 엔티티는 Proxy객체를 가져온다. 따라서 memberClass만 DB에서 조회하고 실제 team을 호출했을 때만 team을 Proxy객체로 가져온다는 의미이다.
public class JPAMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin(); //트랜잭션 시작
try {
Team team = new Team();
team.setName("A");
em.persist(team);
Member member = new Member();
member.setCreatedBy("kim");
member.setTeam(team);
em.persist(member);
em.flush();
em.clear();
Member foundMember = em.getReference(Member.class, member.getId());
System.out.println("foundMember's team = " + foundMember.getTeam().getClass());
tx.commit();
}catch (Exception e){
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
위에 코드를 실행시켜 보면 foundMember 자체는 member Class라는 것을 알 수 있으며, foundMember의 Team은 실제 사용되는 시점에 Proxy 객체를 가져온다는 것을 알 수 있다. 따라서 Lazy 즉 지연로딩으로 조회하면 Proxy로 가져온다.
로직 특성상 member만 90%이상 사용하며 10%만 team을 같이 가져오는 구조라면 지연로딩을 사용하는 것이 효과적이다
즉시 로딩 EAGER를 사용해서 함께 조회
@Entity
public class Member extends BaseEntity{
@Id
@GeneratedValue
private Long id;
@Column(name="USERNAME")
private String username;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="TEAM_ID")
private Team team;
@OneToOne
@JoinColumn(name="LOCKER_ID")
private Locker locker;
}
다시 위에 로직을 실행시켜보면 Lazy와 반대로 Proxy가 아닌 team과 member 모두 실제 값을 가져온다는 것을 알 수 있다
프록시와 즉시로딩 주의
- 가급적 지연 로딩만 사용(특히 실무에서)
- 즉시 로딩을 적용하면 예상하지 못한 SQL 발생
- 즉시 로딩은 JPQL에서 N+1문제를 일으킨다.(추가 쿼리가 N개 나간다)
- @ManyToOne, @OneToOne (XToOne) 은 기본이 즉시 로딩 -> LAZY로 설정
- @OneToMany, @ManyTo Many는 기본이 지연로딩
우선 모든 연관관계는 LAZY로 설정하고 사용하는 것이 좋다. 하지만 fetchJoin을 통해 특정 상황에서 같이 가져오는 방법이 있음
List<Member> memberList = em.createQuery("select m from Member m join fetch m.team", Member.class)
.getResultList();
지연 로딩 활용(이론적인 것)
- Member와 Team은 자주 함께 사용 -> 즉시 로딩
- Member와 Order는 가끔 사용 -> 지연로딩
- Order와 Product는 자주 함께 사용 -> 즉시 로딩
하지만 실무에서는 지연로딩으로 설계하는 것이 중요하다. 즉시 로딩은 상상하지 못한 쿼리가 나간다.
'JPA' 카테고리의 다른 글
영속성 전이 :CASCADE (0) | 2022.10.31 |
---|---|
영속성 전이 :CASCADE (0) | 2022.10.31 |
Proxy(프록시) (0) | 2022.10.30 |
쇼핑몰 만들기 3 - 상속관계 매핑 (0) | 2022.10.30 |
@MappedSuperclass (0) | 2022.10.30 |
Comments