연관관계 매핑
이해를 돕기 위해 Member
엔티티와 Team
엔티티를 사용해보자
하나의 Member는 하나의 Team을 가질 수 있고
하나의 팀은 여러 Member를 가질 수 있기 때문에 이 관계는 1 : N
관계이다
@OneToMany
의 default fetch 설정은 Lazy(지연로딩)이다
-> @XxToMany Many로 끝나면 default가 FetchType.LAZY
(OneToMany, ManyToMany)
@ManyToOne
의 default fetch 설정은 Eager(즉시로딩)이다
-> @XxToOne One으로 끝나면 default가 FetchType.EAGER
(OneToOne, ManyToOne)
@Entity
@Table @Getter @ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
@Id
@Column(name = "member_id")
private Long id;
private String userName;
@ManyToOne
@JoinColumn(name = "team_id")
private Team team;
// Getter, Setter, Constructor...
}
@Entity
@Table @Getter @ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Team {
@Id
@Column(name = "team_id")
private Long id;
private String name;
// Getter, Setter, Constructor
}
@ManyToOne
의 default 설정값이 FetchType.EAGER
인데 따로 설정을 안해줬기 때문에 즉시로딩이다
-> 동시에 조회가 된다
-> 대부분의 JPA 구현체는 즉시로딩을 최적화하기 위해 가능하면 조인 쿼리를 사용한다
SELECT m.member_id, m.team_id, m.userName, t.team_id, t.name
FROM
Member m
LEFT OUTER JOIN
Team t
ON m.team_id = t.team_id
WHERE m.member_id = 0;
로딩되는 시점에 Lazy 로딩 설정이 되어있는 Team 엔티티는 프록시 객체로 가져온다
@Entity
public class Member {
@Id
@Column(name = "member_id")
private Long id;
@Column(name = "user_name")
private String userName;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
// Getter, Setter, Constructor...
}
@Entity
public class Team {
@Id
@Column(name = "team_id")
private Long id;
@Column(name = "name")
private String name;
// Getter, Setter, Constructor
}
System.out.println("1. 회원 객체 조회");
Member member = entityManager.find(Member.class, 0L);
System.out.println("2. 회원 이름 조회");
System.out.println("회원 이름 : " + member.getUsername());
System.out.println("3. 팀 객체 조회");
Team team = member.getTeam(); // Proxy 객체이기 때문에 실제 조회는 team.getXXX 할때 발생합니다.
System.out.println(team.getClass());
System.out.println("4. 팀 이름 조회");
System.out.println("팀 이름 : " + team.getName()); // Proxy 객체 초기화
System.out.println(team.getClass());
실행하면
1. 회원객체 조회
SELECT m.member_id, m.team_id, m.user_name
FROM
Member m
WHERE m.member_id = 0;
2. 회원 이름 조회
회원 이름 : 회원1
3. 팀 객체 조회
class TIL.jpa.Domain.Team$HibernateProxy$hbJa4wRu
4. 팀 이름 조회
SELECT t.team_id, t.name
FROM
Team t
WHERE t.team_id = 0;
팀 이름 : 팀1
class TIL.jpa.Domain.Team$HibernateProxy$hbJa4wRu
다음과 같이 출력되는데
해결방법 : JPQL을 사용하여 DB에서 데이터를 가져올 때 처음부터 연관된 데이터까지 같이 가져오게 하는 방법
@Query() 어노테이션을 사용한다
@Query("SELECT m FROM Member m JOIN FETCH m.team")
List<Member> members = findAllFetchTeam();