@Entity
@Getter
@Setter
@NoArgsConstructor
public class Member extends BaseTimeEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
}
Fetch = LAZY를 사용해 Member 객체만 실제 Entity로 가져오고 Team 객체는 빈껍데기인 프록시 객체로 가져온다.
final Team team = Team.of("teamA");
em.persist(team);
final Member member = new Member();
member.setName("hello");
member.addTeam(team);
em.persist(member);
em.flush();
em.clear();
final Member findMember = em.find(Member.class, member.getId());
System.out.println("findMember.getClass() = " + findMember.getClass());
System.out.println("findMember.getTeam().getClass() = " + findMember.getTeam().getClass());
System.out.println("=====================");
findMember.getTeam().getName();
System.out.println("=====================");
- 쿼리를 보면 Member 객체의 값들만 select 해서 가져오는 것을 확인할 수 있다. 객체를 가져오는 것을 확인할 수 있다.(값 X)
- Team 객체의 값들이 필요할 때 그때서야 DB에서 쿼리를 조회해서 값을 가져오는 것을 확인할 수 있다.
@Entity
@Getter
@Setter
@NoArgsConstructor
public class Member extends BaseTimeEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "team_id")
private Team team;
}
final Team team = Team.of("teamA");
em.persist(team);
final Member member = new Member();
member.setName("hello");
member.addTeam(team);
em.persist(member);
em.flush();
em.clear();
final Member findMember = em.find(Member.class, member.getId());
System.out.println("findMember.getClass() = " + findMember.getClass());
System.out.println("findMember.getTeam().getClass() = " + findMember.getTeam().getClass());
System.out.println("=====================");
findMember.getTeam().getName();
System.out.println("=====================");
- Member를 가져올 때 Team도 조인해서 같이 가져오는 것을 확인할 수있다.
- 또한 Member와 연관관계인 Team이 프록시 객체가 아닌 실제 엔티티인 것을 확인할 수 있다. (값 O)
가급적 지연 로딩(LAZY)를 사용해야 한다.
만약 Member와 연관관계가 Team 뿐만 아니라 수십개 있다고 가정했을 때
Member 객체를 조회했을 뿐인데 수 많은 조인 컬럼들이 생기게 된다.
이는 성능에도 문제를 일으킬 수 있다.
final List<Member> memberList =
em.createQuery("select m from Member m", Member.class)
.getResultList();
SQL : select * from Member
SQL : select * from Team where TEAM_ID = xxx
- JPQL을 사용해서 Member 클래스들 모두 조회해서 가져왔는데 Member와 연관되어 있는 Team이 EAGER로 되어있기 때문에 DB에서 Team을 다시 한번 가져오게 된다.
final Team teamA = Team.of("teamA");
em.persist(teamA);
final Team teamB = Team.of("teamB");
em.persist(teamB);
final Member member1 = new Member();
member1.setName("hello");
member1.addTeam(teamA);
final Member member2 = new Member();
member2.setName("hello");
member2.addTeam(teamB);
em.persist(member1) ;
em.persist(member2);
em.flush();
em.clear();
final List<Member> memberList = em.createQuery("select m from Member m", Member.class)
.getResultList();
Member 객체를 조회하고 난 후 Member 객체와 연관관계맺은 Team 객체가 다르다면 각각 PK를 통해서 다시 찾아야 하므로 Team을 조회하는 쿼리가 계속 늘어나게 된다.
때문에 이러한 문제를 방지하기 위해 연관관계는 LAZY로 바꾸고 fetch Join을 사용해서 한번에 가져와야한다.
final List<Member> memberList = em.createQuery("select m from Member m join fetch m.team", Member.class) .getResultList();
페치 조인 한방 쿼리로 Member와 Team 객체의 값을 한번에 모두 가져온다.