프로젝트 git url | github.com/rtef23/JpaStudy |
필요 | 1. docker 2. docker-compose |
프로젝트 정보 | mysql : 5.7 - docker image java : 1.8 |
지연 로딩
- 연관 관계에 있는 엔티티를 데이터베이스에서 조회할 때 같이 조회하는 것이 아니라, 연관 관계에 있는 엔티티를 사용하는 경우 추가 쿼리로 데이터베이스에서 조회하도록 하는 방법
- 연관된 엔티티를 fetch = FetchType.LAZY로 설정하면 된다.
- 최초 조회시에 연관 관계의 엔티티는 hibernate 프록시 객체로 들어가 있게 된다.
- @OneToMany, @ManyToMany (xxxToMany)는 지연 로딩이 기본 값이다.
- 가급적 지연 로딩을 사용하는 것을 추천한다.
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
...
}
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "team_id")
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members;
...
}
- 조회된 데이터의 리스트를 돌면서 N + 1 문제가 동일하게 발생할 수 있지만, fetch join과 같은 방법을 이용하여 해결할 수 있다.
List<Member> findMembers = entityManager.createQuery("select m from Member m join fetch m.team", Member.class).getResultList();
- 아래의 코드에서 Team 엔티티를 조회하는 시점은 findMember1.getTeam().getName()을 호출한 시점에서 데이터베이스에서 조회한다.(getTeam을 호출한 시점이 아닌 getName을 호출한 시점)
Member findMember1 = entityManager.find(Member.class, member1.getId());
System.out.println("#### founded member name : " + findMember1.getName());
System.out.println("#### founded team name : " + findMember1.getTeam().getName());
즉시 로딩
- 연관관계에 있는 엔티티를 최초 조회시 조인하여 함께 조회하는 방법
- 연관된 엔티티를 fetch = FetchType.EAGER 로 설정하면 된다.
- 즉시 로딩은 예기치 않은 쿼리를 생성할 수 있기 때문에 가능한 지양하는 편이 좋다.
- JPQL에서 N + 1 문제를 일으킬 수 있다.
Team team = new Team();
team.setName("test-team-1");
entityManager.persist(team);
Team team2 = new Team();
team2.setName("test-team-2");
entityManager.persist(team2);
Member member1 = new Member();
member1.setName("test-member-1");
member1.setTeam(team);
entityManager.persist(member1);
Member member2 = new Member();
member2.setName("test-member-2");
member2.setTeam(team);
entityManager.persist(member2);
Member member3 = new Member();
member3.setName("test-member-3");
member3.setTeam(team2);
entityManager.persist(member3);
entityManager.flush();
entityManager.clear();
List<Member> findMembers = entityManager.createQuery("select m from Member m", Member.class).getResultList();
//서로 다른 team인 team, team2를 조회하기 위해서 2번의 team 테이블을 조회하는 쿼리가 실행되게 된다.
- @ManyToOne, @OneToOne은 (xxxToOne) 즉시 로딩이 기본값이다.
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
private String name;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "team_id")
private Team team;
...
}
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "team_id")
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members;
...
}
- 아래 코드에서 Team은 Member 조회시 함께 조회하게 된다.
Member findMember1 = entityManager.find(Member.class, member1.getId());
System.out.println("#### founded member name : " + findMember1.getName());
System.out.println("#### founded team name : " + findMember1.getTeam().getName());
'JPA' 카테고리의 다른 글
[JPA] 17. 값 타입 (0) | 2021.01.21 |
---|---|
[JPA] 16. 영속성 전이(CASCADE) (0) | 2021.01.18 |
[JPA] 14. Hibernate 프록시 (0) | 2021.01.15 |
[JPA] 13. @MappedSuperclass (0) | 2021.01.11 |
[JPA] 12. 상속 관계 매핑 (0) | 2021.01.11 |