728x90
반응형
즉시 로딩과 지연 로딩
- 이전 포스트에서 프록시에 대해 배웠다.
- 해당 객체와 연관된 다른 객체를 어떤 시점에 불러올지 , 어떤 타입으로 형성되는지 알아봤다.
- JPA는 이런 프록시 기술을 사용해서 지연로딩을 사용한다.
객체 생성 코드
@Entity
@Data
@NoArgsConstructor(access = AccessLevel.PROTECTED)//기본생성자 protected
@ToString(of = {"id","username","age"})
public class Member extends BaseEntity {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
private int age;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "team_id")
Team team;
public Member(String username, int age, Team team) {
this.username = username;
this.age = age;
if (team != null) {
changeTeam(team);
}
}
public Member(String teamA) {
this.username = teamA;
}
private void changeTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
public Member(String username, int age) {
this.username = username;
this.age = age;
}
}
Member와 Team객체 조회해보기
@Test
@Transactional
public void testLazyLoading(){
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member("memberA");
em.persist(member);
member.changeTeam(team);
em.flush();
em.clear();
Member findMember = em.find(Member.class, member.getId());
System.out.println("findMember = " + findMember.getClass());
System.out.println("findMember.getTeam = " + findMember.getTeam().getClass());
System.out.println("findMember.getTeam Proxy 초기화 = " + findMember.getTeam().getName());
}
DDL 및 출력 결과
- 실제로 Team의 필드값을 호출하기 전까지는 Proxy객체로 남아있다.
- 필드값을 호출한 시점에는 select구문이 나가며 Proxy객체가 초기화된다. [지연로딩]
select
member0_.member_id as member_id1_2_0_,
member0_.created_by as created_by2_2_0_,
member0_.created_date as created_date3_2_0_,
member0_.last_modifed_by as last_modifed_by4_2_0_,
member0_.last_modifed_date as last_modifed_date5_2_0_,
member0_.age as age6_2_0_,
member0_.team_id as team_id8_2_0_,
member0_.username as username7_2_0_
from
member member0_
where
member0_.member_id=?
//System.out.println("findMember = " + findMember.getClass()) 결과
findMember = class study.jpa.queryDSL.domain.Member
//System.out.println("findMember.getTeam = " + findMember.getTeam().getClass()) 결과
findMember.getTeam = class study.jpa.queryDSL.domain.Team$HibernateProxy$2lVm0R3o
select
team0_.team_id as team_id1_3_0_,
team0_.created_by as created_by2_3_0_,
team0_.created_date as created_date3_3_0_,
team0_.last_modifed_by as last_modifed_by4_3_0_,
team0_.last_modifed_date as last_modifed_date5_3_0_,
team0_.name as name6_3_0_
from
team team0_
where
team0_.team_id=?
//System.out.println("findMember.getTeam Proxy 초기화 = " + findMember.getTeam().getName()) 결과
findMember.getTeam Proxy 초기화 = teamA
지연 로딩(Lazy Loading)
- 로딩되는 시점에 Lazy로딩 설정이 되어 있는 Team엔티티는 프록시 객체로 가져온다.
- 실제 객체를 사용하는 시점에 초기화가 되며, DB에 쿼리가 나간다.
즉시 로딩(Eager Loading)
- 대부분의 JPA구현체는 조인을 사용해서 한번에 함꼐 조인하려고 한다.
- 즉시 로딩시에는 하나의 쿼리에 연관관계를 모두 조인해서 가져온다.
- getTeam을 통해 가져온 객체도 프록시객체가 아닌 실제 엔티티객체다.
프록시와 즉시 로딩시 주의 점
- 실무에서는 모두 지연로딩을 사용한다.
- 즉시 로딩시에는 모든 연관관계를 불러오는데 예상하지 못한 구문이 나올 수 있다. (모든 연관관계를 가져오기 때문)
- 즉시 로딩은 JPQL에서 N+1문제를 일으킨다.(하나의 쿼리로 N개의 추가 쿼리가 나감)
- 지연로딩을 사용하되 쿼리가 추가적으로 나가지 않게 하는 방법이있다.
- JPQL의 fetch join을 사용한다.
- 엔티티 그래프와 어노테이션, 배치 사이즈 설정으로 해결하는 방법도 있다.
- XXXToOne어노테이션들은 기본이 즉시 로딩이므로 꼭 Lazy로 명시하여 사용하자.
- OneToMany, ManyToMany는 기본이 지연로딩이다.
728x90
반응형
'Spring > JPA' 카테고리의 다른 글
@Where Deprecated되고 새로 쓰이는 @SQLRestriction (1) | 2024.11.20 |
---|---|
JPA - DB 연결 예외 : 'url' attribute is not specified and no embedded datasource could be configured. (0) | 2024.06.14 |
JPA - Proxy (2) | 2023.12.10 |
JPA - MappedSuperClass (0) | 2023.12.10 |
JPA - 상속관계매핑 (0) | 2023.12.09 |