지연로딩 LAZY
사용방법
@Entity
public class Member {
public Member() {
}
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name="USERNAME", nullable = false)
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
@OneToOne
Locker locker;
}
연관관계에서, fetch = FetchType.LAZY 해 놓으면
프록시로, team을 프록시로 일단 가져온다.
Team team1 = new Team();
team1.setName("Team1");
em.persist(team1);
Member member1 = new Member();
member1.setName("member1");
member1.setTeam(team1);
em.persist(member1);
em.flush();
em.clear();
Member findedMember = em.find(Member.class, member1.getId());
System.out.println("findedMember.getTeam().getClass() = " + findedMember.getTeam().getClass());
tx.commit();
findedMember.getTeam().getClass() = class hellojpa.Team$HibernateProxy$chtRE5JI
LAZY 이름 그대로 지연 로딩이다.
team에 접근한 후에 그제서야 select해서 가져올 것이다.
이 케이스가 바로,
비즈니스 로직 상 Member를 쓸 때 Team을 사용할 수도, 안할 수도 있을 때 쓰는 경우 좋고,
반대로 Member를 쓰면 Team을 거의 짝꿍처럼 쓰는 경우는
EAGER
@Entity
public class Member {
public Member() {
}
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name="USERNAME", nullable = false)
private String name;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "TEAM_ID")
private Team team;
@OneToOne
Locker locker;
}
Team team1 = new Team();
team1.setName("Team1");
em.persist(team1);
Member member1 = new Member();
member1.setName("member1");
member1.setTeam(team1);
em.persist(member1);
em.flush();
em.clear();
Member findedMember = em.find(Member.class, member1.getId());
System.out.println("findedMember.getTeam().getClass() = " + findedMember.getTeam().getClass());
tx.commit();
이렇게 해 보면 Member 조회 쿼리가 나갈 때 join해서 team도 바로 가져오고,
그에 따라 team도 프록시로 가져올 이유가 없어서 team의 클래스는 프록시가 아닌 그냥 Team이다.
근데, 실무에서는 LAZY만 쓴다.
예상치 못한 쿼리가 날라간다고 한다.
나중에 JPQL 배울 때 배우겠지만,
Team team1 = new Team();
team1.setName("Team1");
em.persist(team1);
Member member1 = new Member();
member1.setName("member1");
member1.setTeam(team1);
em.persist(member1);
em.flush();
em.clear();
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
tx.commit();
이렇게 조회부분 그냥 쿼리로 날려봤더니.
Hibernate:
/* select
m
from
Member m */ select
m1_0.MEMBER_ID,
m1_0.locker_id,
m1_0.USERNAME,
m1_0.TEAM_ID
from
Member m1_0
Hibernate:
select
t1_0.TEAM_ID,
t1_0.name
from
Team t1_0
where
t1_0.TEAM_ID=?
join쿼리로 안나간다.
그냥 Member 조회해보다 Team도 필요해서 팀도 쿼리 날린 것 같다.
물론,
Team team1 = new Team();
team1.setName("Team1");
em.persist(team1);
Member member1 = new Member();
member1.setName("member1");
member1.setTeam(team1);
em.persist(member1);
em.flush();
em.clear();
List<Member> members = em.createQuery("select m from Member m join fetch m.team", Member.class).getResultList();
tx.commit();
이렇게 join fetch 해서 같이 가져오면 되긴 한다.
Hibernate:
/* select
m
from
Member m
join
fetch m.team */ select
m1_0.MEMBER_ID,
m1_0.locker_id,
m1_0.USERNAME,
t1_0.TEAM_ID,
t1_0.name
from
Member m1_0
join
Team t1_0
on t1_0.TEAM_ID=m1_0.TEAM_ID
그럼 이렇게 join 해서 나간다.
그래도 여튼 가급적이면 지연로딩만 사용하자.
근데,
@ManyToOne, @OneToOne 같이
XToOne은 즉시로딩이 기본이다.
그래서 우리가 이걸 명시적으로 fetch=FetchType.LAZY로 기본으로 설정 해 주어야 한다.
그럼 이제 어떻게 할까.
Member와 Team을 자주 함께 사용한다 -> 즉시 로딩
Member와 Order는 가끔 사용한다 -> 지연 로딩
Order와 Product는 자주 함께 사용한다 -> 즉시 로딩
....
이라고 하는데,
실무에서는 모두 지연로딩으로 하라고 한다.
저건 그냥 이론적인 거고.
'JPA > JPA 기본' 카테고리의 다른 글
30. 실전 연관관계 관리 (0) | 2023.10.29 |
---|---|
29. 영속성 전이와 고아 객체 (0) | 2023.10.28 |
27. 프록시 (0) | 2023.10.27 |
25. Mapped Superclass 매핑 정보 상속 (0) | 2023.10.27 |
24. 상속관계 매핑 (0) | 2023.10.26 |