SW/Spring

Spring Data JPA에서 동적 엔티티 그래프 활용하기

얇은생각 2024. 8. 22. 07:30
반응형

Java 애플리케이션에서 데이터베이스와의 상호작용을 효율적으로 관리하기 위해 JPA(Java Persistence API)와 그 구현체인 Hibernate는 매우 중요한 역할을 합니다. 이 기술들은 관계형 데이터베이스에 저장된 데이터를 손쉽게 조회하고 처리할 수 있는 방법을 제공하며, 이러한 접근 방식을 통해 성능 최적화를 이루는 것이 개발자들에게 중요한 과제 중 하나입니다. 특히, 복잡한 엔티티 관계가 존재하는 대규모 애플리케이션에서는 불필요한 데이터베이스 쿼리를 최소화하는 것이 핵심입니다.

이 글에서는 Spring Data JPA에서 제공하는 **엔티티 그래프(Entity Graph)**를 활용하여 데이터베이스 조회 성능을 최적화하는 방법을 알아보고, 이를 동적으로 적용할 수 있는 기법에 대해 자세히 살펴보겠습니다.

 

Spring Data JPA에서 동적 엔티티 그래프 활용하기

 

엔티티 그래프(Entity Graph)란?

엔티티 그래프는 JPA 2.1에 도입된 기능으로, 엔티티와 그 연관 데이터를 조회할 때 **명시적인 페치 플랜(Fetch Plan)**을 정의할 수 있는 기능입니다. 이 기능을 통해 데이터베이스에서 가져올 연관 데이터를 미리 정의할 수 있으며, 이를 통해 N+1 문제를 해결하거나 수동으로 JOIN 쿼리를 작성할 필요 없이 데이터를 효율적으로 조회할 수 있습니다.

일반적으로 JPA는 연관된 엔티티를 EAGER 또는 LAZY 방식으로 조회합니다. EAGER는 즉시 로딩 방식으로 연관된 모든 데이터를 한꺼번에 가져오지만, 자주 사용되지 않는 데이터를 불필요하게 로딩하여 성능 저하를 유발할 수 있습니다. 반면 LAZY는 필요할 때만 데이터를 가져오는 지연 로딩 방식이지만, 트랜잭션 내에서 적절히 데이터를 로딩하지 않으면 N+1 문제를 일으킬 수 있습니다. 이러한 문제들을 해결하기 위해 등장한 것이 엔티티 그래프입니다.

엔티티 그래프를 사용하면 개발자는 필요한 데이터만을 명확하게 정의하여, 필요한 데이터만 조회할 수 있게 되어 데이터베이스 조회 성능을 극대화할 수 있습니다.

 

 

Spring Data JPA에서의 엔티티 그래프 사용법

Spring Data JPASpring Boot 2.1.0부터 엔티티 그래프를 기본적으로 지원합니다. 엔티티 그래프는 @NamedEntityGraph@EntityGraph 애너테이션을 사용하여 정의할 수 있습니다. 이를 사용해 Spring Data JPA에서 명시적으로 데이터를 가져오는 방법을 설정할 수 있습니다.

 

엔티티 예시

아래와 같은 Owner와 Pet 엔티티를 가정해 보겠습니다.

@Entity
public class Owner extends Person {

    @Column(name = "address")
    private String address;

    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "owner_id")
    @OrderBy("name")
    private List<Pet> pets = new ArrayList<>();
}

@Entity
public class Pet extends NamedEntity {

    @Column(name = "birth_date")
    private LocalDate birthDate;

    @ManyToOne
    @JoinColumn(name = "type_id")
    private PetType type;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "pet_id")
    private Set<Visit> visits = new LinkedHashSet<>();
}
 

이 예시에서 Owner와 Pet은 주인-반려동물의 관계를 나타내며, Owner는 여러 Pet을 가질 수 있습니다. 이제 이 엔티티를 바탕으로 다양한 조회 시나리오에서 엔티티 그래프를 활용할 수 있습니다.

 

 

엔티티 그래프를 사용한 데이터 조회

예를 들어, Owner와 그의 반려동물 정보를 UI에 표시하고자 할 때, 아래와 같은 엔티티 그래프를 사용할 수 있습니다.

@EntityGraph(attributePaths = { "pets" })
Page<Owner> findByLastNameStartingWithIgnoreCase(@Nullable String lastName, Pageable pageable);
 

위 코드는 주인의 성을 기준으로 검색한 후, 해당 주인과 그의 반려동물 정보를 한 번에 가져오는 쿼리를 생성합니다. @EntityGraph 애너테이션을 통해 pets라는 속성을 명시적으로 가져오도록 설정하여 추가적인 쿼리 없이 데이터를 효율적으로 가져올 수 있습니다.

 

 

동적 엔티티 그래프의 필요성

하지만, 애플리케이션이 커질수록 다양한 조회 요구 사항이 발생할 수 있습니다. 예를 들어, 간단한 주인 정보만 필요한 경우와 더 상세한 정보(예: 반려동물의 방문 기록까지 포함)를 가져와야 하는 경우가 다릅니다. 이런 상황에서는 다양한 엔티티 그래프를 미리 정의해두고 필요할 때마다 적절한 그래프를 적용하는 것이 이상적입니다.

Spring Data JPA에서는 하나의 리포지토리 메서드에 하나의 @EntityGraph 애너테이션만 사용할 수 있습니다. 즉, 엔티티 그래프를 동적으로 변경하고자 한다면 코드의 복잡도가 증가할 수 있으며, 각 조회 요구 사항마다 새로운 메서드를 추가해야 하는 번거로움이 발생할 수 있습니다. 이로 인해 코드가 점점 복잡해지고 유지보수성이 떨어질 수 있습니다.

 

 

동적 엔티티 그래프 적용하기

이 문제를 해결하기 위해, Cosium이라는 회사에서 제공하는 Spring Data JPA EntityGraph 라이브러리를 활용할 수 있습니다. 이 라이브러리는 동적으로 엔티티 그래프를 생성하고 이를 JPA 쿼리에 적용할 수 있는 기능을 제공합니다. 이를 통해 각 상황에 맞는 엔티티 그래프를 동적으로 정의하고 사용할 수 있습니다.

 

 

사용 방법

먼저, 해당 라이브러리를 프로젝트에 추가해야 합니다. 이를 위해 pom.xml 파일에 아래와 같은 의존성을 추가합니다.

<dependency>
  <groupId>com.cosium.spring.data</groupId>
  <artifactId>spring-data-jpa-entity-graph</artifactId>
  <version>3.0.1</version>
</dependency>
 

 

그리고 Spring Boot 애플리케이션 클래스에서 EntityGraphJpaRepositoryFactoryBean을 사용하도록 설정합니다.

 

 

@SpringBootApplication
@EnableJpaRepositories(repositoryFactoryBeanClass = EntityGraphJpaRepositoryFactoryBean.class)
public class PetClinicApplication {
    // 애플리케이션 코드
}
 

 

이제 리포지토리 메서드에서 엔티티 그래프를 파라미터로 받아들일 수 있습니다.

 

 

Optional<Owner> findById(Integer id, EntityGraph entityGraph);

 

 

동적 엔티티 그래프를 생성할 수 있도록 해주는 빌더 패턴도 사용할 수 있습니다. 예를 들어, 주인의 반려동물과 그들의 방문 기록을 함께 가져오는 엔티티 그래프를 다음과 같이 생성할 수 있습니다.

 

 

OwnerEntityGraph entityGraph = OwnerEntityGraph
    .____() // 루트 그래프 가져오기
    .pets().type() // 반려동물 및 유형 조회
    .____ // 루트로 돌아가기
    .pets().visits() // 반려동물 방문 기록 조회
    .____
    .____();
Owner owner = this.ownerRepository.findById(ownerId, entityGraph)
    .orElseThrow();
 

이처럼 동적 엔티티 그래프를 사용하면 코드가 복잡해지는 것을 방지할 수 있으며, 특정 상황에 맞게 데이터를 효율적으로 조회할 수 있습니다.

 

 

결론

엔티티 그래프는 JPA에서 데이터 조회를 최적화할 수 있는 강력한 도구로, 복잡한 데이터 모델을 다루는 애플리케이션에서 성능 향상을 도울 수 있습니다. Spring Data JPA에서 정적으로 정의된 엔티티 그래프 외에도 동적으로 그래프를 생성하고 사용할 수 있는 방법을 통해 코드의 복잡성을 줄이고 유지보수성을 높일 수 있습니다.

동적 엔티티 그래프는 데이터베이스 조회 시 다양한 요구 사항에 유연하게 대응할 수 있도록 도와주며, 성능 최적화를 위한 필수 도구로 자리 잡고 있습니다. 이를 통해 개발자는 더 효율적이고 가독성이 좋은 코드를 작성할 수 있으며, 엔터프라이즈 애플리케이션의 데이터 처리 성능을 크게 개선할 수 있습니다.

따라서, JPA를 사용하여 복잡한 데이터베이스 구조를 다루고 있다면, 동적 엔티티 그래프의 활용을 적극 고려해보는 것이 좋습니다.

반응형