안녕하세요 이번 글에서는 JPA에서의 지연 로딩과 즉시 로딩에 대해서 알아보겠습니다.
두 가지 Entity를 예시로 만들겠습니다.
Member
@Entity
@Getter @Setter
public class Member{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "member_id")
private Long Id;
private String username;
private int age;
@ManyToOne()
@JoinColumn(name = "team1_id")
private Team team;
Team
@Entity
@Getter
@Setter
public class Team {
@Id
@GeneratedValue
@Column(name = "team_id")
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
연관관계의 주인은 Member로 설정하고 다대일 , 일대다 양방향을 사용하겠습니다.
이 상태에서 Member를 조회해봅시다.
@Test
public void LoadingTest(){
//테스트용 데이터를 입력합니다.
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
Team teamC = new Team("teamC");
em.persist(teamA);
em.persist(teamB);
em.persist(teamC);
Member member = new Member("memberA");
Member memberB = new Member("memberB");
Member memberC = new Member("memberC");
member.changeTeam(teamA);
memberB.changeTeam(teamB);
memberC.changeTeam(teamC);
em.persist(member);
em.persist(memberB);
em.persist(memberC);
//초기화
em.flush();
em.clear();
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
}
위처럼 각각의 멤버와 팀을 생성한 뒤 멤버를 조회한 다음 쿼리를 확인해 봅시다.
[ 즉시 로딩 ]
가독성이 좀... ㅎㅎ
위에서부터 차근차근 보면 member를 조회하는 select 쿼리가 한번 실행됩니다.
그다음 각 member들이 가지고 있는 Team들을 조회하는 select 쿼리가 3번 실행되는 것을 확인할 수 있습니다.
이 처럼 즉시 로딩을 사용할 시 데이터가 많아진다면 필요하지 않은 쿼리들도 어마어마하게 많이 생성될 수 있습니다.
위 같은 이유로 되도록 즉시 로딩보다는 지연 로딩을 권장합니다.
그럼 지연 로딩을 사용해서 결과를 확인해 보겠습니다.
Member의 @ManyToOne fetch 속성을 LAZY로 변강 하겠습니다. ( @OneToMany는 기본 속성이 LAZY )
@Entity
@Getter @Setter
public class Member{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "member_id")
private Long Id;
private String username;
private int age;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "team1_id")
private Team team;
다시 테스트 코드를 실행해 보면
Member를 조회하는 select 쿼리만 실행된 것을 확인할 수 있습니다.
이때 조회된 Member 객체에 들어있는 Team객체는 프락시 객체가 Team을 상속한 상태로 생성되며
Team을 조회하는 순간 select 쿼리가 실행됩니다.
테스트 코드의 조회된 Member에서 getter를 사용하여 Team을 호출하여 보면
@Test
public void LoadingTest(){
//테스트용 데이터를 입력합니다.
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
Team teamC = new Team("teamC");
em.persist(teamA);
em.persist(teamB);
em.persist(teamC);
Member member = new Member("memberA");
Member memberB = new Member("memberB");
Member memberC = new Member("memberC");
member.changeTeam(teamA);
memberB.changeTeam(teamB);
memberC.changeTeam(teamC);
em.persist(member);
em.persist(memberB);
em.persist(memberC);
//초기화
em.flush();
em.clear();
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
for (Member findMember : members) {
System.out.println(" ======================================================= " );
System.out.println("findMember.Team = " + findMember.getTeam());
System.out.println(" ======================================================= " );
}
}
각각 의 Member 객체에서 Team을 호출하는 순간 select 쿼리가 실행되는 것을 확인할 수 있습니다.
결론
- JPA에서는 즉시 로딩 X, 지연 로딩을 주로 사용해라!
- 한 번에 전부 조회가 필요한 경우 즉시 로딩이 아닌 fetch조인 또는 엔 티틴 그래프를 사용
감사합니다 ^^
참고 영상 : https://www.inflearn.com/course/ORM-JPA-Basic
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 본 강의는 자바 백엔
www.inflearn.com