가장 중요한 것은 필요한 정보만큼의 쿼리를 날리는 것이다.
조인을 하지 않고 너무 적은 정보를 가져와 발생하는 예상하기 어려운 N+1 문제도,
서비스 동작시에 필요없는 정보도 조인으로 가져오는 것도 문제다.
같은 객체를 DB에서 가져오더라도, 필요한 정보의 양이 다르면 메소드를 분리해야 한다.
EntityGraph를 사용하든 Fetch Join을 사용하든 서비스에서 필요한 정보의 양은 서비스의 동작 마다 다르다.
코드 예시를 보자
Team Entity
@Entity
@Getter
@NamedEntityGraph(name = "Team.withAll", attributeNodes = {
@NamedAttributeNode("tags"),
@NamedAttributeNode("zones"),
@NamedAttributeNode("managers"),
@NamedAttributeNode("members")})
@NamedEntityGraph(name = "Team.withTagsAndManager", attributeNodes = {
@NamedAttributeNode("tags"),
@NamedAttributeNode("managers"),
})
@NamedEntityGraph(name = "Team.withZonesAndManager", attributeNodes = {
@NamedAttributeNode("zones"),
@NamedAttributeNode("managers"),
})
@NamedEntityGraph(name = "Team.withManager", attributeNodes = {
@NamedAttributeNode("managers"),
})
public class Team {
@Id
@GeneratedValue
private Long id;
@ManyToMany
@Builder.Default
private Set<Account> managers = new HashSet<>();
@ManyToMany
@Builder.Default
private Set<Account> members = new HashSet<>();
@ManyToMany
@Builder.Default
private Set<Tag> tags = new HashSet<>();
@ManyToMany
@Builder.Default
private Set<Zone> zones = new HashSet<>();
}
공모전 팀빌딩을 해주는 서비스의 팀 엔티티이고 연관관계 필드만 남겼다.
연관관계로는 팀에 속한 매니저, 멤버, 지역정보, 관심태그가 걸려있다.
Team Repsiotry
팀에 지역정보, 관심태그, 멤버를 업데이트 전에 팀 엔티티에 접근한 사람이 매니저인지 확인하기 위해 팀의 매니저 정보가 필요하다.
@Transactional(readOnly = true)
public interface TeamRepository extends JpaRepository<Team, Long> {
boolean existsByPath(String path);
// findByPath 발생 시 Team의 member, manager, zones, tags 모두 필요
@EntityGraph(value = "Team.withAll", type = EntityGraph.EntityGraphType.LOAD)
Team findByPath(String path);
@EntityGraph(value = "Team.withTagsAndManager", type = EntityGraph.EntityGraphType.FETCH)
Team findTeamWithTagsByPath(String path);
@EntityGraph(value = "Team.withZonesAndManager", type = EntityGraph.EntityGraphType.FETCH)
Team findTeamWithZonesByPath(String path);
@EntityGraph(value = "Team.withManager", type = EntityGraph.EntityGraphType.FETCH)
Team findTeamWithManagersByPath(String path);
}
따라서 팀 정보를 조회할 때는 findByPath 메소드를, 지역정보를 업데이트 할때는 지역정보와 매니저만 EAGER, 관심태그를 업데이트 할 때는 관심 태그와 매니저만 EAGER, 연관관계가 걸리지 않은 엔티티의 필드를 업데이트 할 때는 매니저만 EAGER로 가져온다.
참고
인프런 - 스프링과 JPA 기반 웹 앱플리케이션 개발(백기선) 강의