SpringData JPA 및 Named Entity Graphs

1. 개요

간단히 말해서 엔티티 그래프는 JPA 2.1에서 쿼리를 설명하는 또 다른 방법입니다. 이를 사용하여 더 나은 성능의 쿼리를 작성할 수 있습니다.

이 튜토리얼에서는 간단한 예제를 통해 SpringData JPA로 엔티티 그래프를 구현하는 방법을 배웁니다.

2. 실체

먼저, 여러 특성을 가진 Item 이라는 모델을 만들어 보겠습니다 .

@Entity public class Item { @Id private Long id; private String name; @OneToMany(mappedBy = "item") private List characteristics = new ArrayList(); // getters and setters }

이제 C Haracteristic 엔티티를 정의 해 보겠습니다 .

@Entity public class Characteristic { @Id private Long id; private String type; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn private Item item; //Getters and Setters }

코드에서 볼 수 있듯이 항목 엔티티 의 특성 필드 와 특성 엔티티 의 항목 필드는 모두 fetch 매개 변수를 사용하여 느리게로드 됩니다. 그래서 여기서 우리의 목표는 런타임에 열심히로드하는 것입니다.

3. 엔티티 그래프

SpringData JPA에서는 @NamedEntityGraph@EntityGraph 주석조합을 사용하여 엔티티 그래프를 정의 할 수 있습니다 . 또는 @EntityGraph 주석attributePaths 인수 만 사용하여 임시 엔티티 그래프를 정의 할 수도 있습니다 .

어떻게 할 수 있는지 봅시다.

3.1. 와 @NamedEntityGraph

먼저 항목 엔티티 에서 직접 JPA의 @NamedEntityGraph 주석을 사용할 수 있습니다 .

@Entity @NamedEntityGraph(name = "Item.characteristics", attributeNodes = @NamedAttributeNode("characteristics") ) public class Item { //... }

그런 다음 저장소 메서드 중 하나에 @EntityGraph 주석을 연결할 수 있습니다 .

public interface ItemRepository extends JpaRepository { @EntityGraph(value = "Item.characteristics") Item findByName(String name); }

코드에서 볼 수 있듯이, 우리는 개체 그래프의 이름을 통과 한 우리가 이전에 만든 항목 개체, 받는 @EntityGraph의 주석을. 메서드를 호출 할 때 이것이 SpringData가 사용할 쿼리입니다.

@EntityGraph 어노테이션 의 유형 인수 기본값 은 EntityGraphType.FETCH 입니다. 이것을 사용하면 SpringData 모듈은 지정된 속성 노드에 FetchType.EAGER 전략을 적용합니다 . 다른 경우에는 FetchType.LAZY 전략이 적용됩니다.

따라서 우리의 경우 @OneToMany 주석 의 기본 가져 오기 전략 이 게으른 경우에도 특성 속성이 열심히로드됩니다 .

여기서 한 가지 문제점 은 정의 된 가져 오기 전략이 EAGER이면 해당 동작을 LAZY로 변경할 수 없다는 것 입니다. 이는 후속 작업이 실행 중 나중에 열렬하게 가져온 데이터를 필요로 할 수 있으므로 의도적으로 설계된 것입니다.

3.2. @NamedEntityGraph 없이

또는, 우리는, 너무, 임시 개체 그래프를 정의 할 수 있습니다attributePaths.

Item 부모 를 열심히로드하는 CharacteristicsRepository에 임시 엔티티 그래프를 추가해 보겠습니다 .

public interface CharacteristicsRepository extends JpaRepository { @EntityGraph(attributePaths = {"item"}) Characteristic findByType(String type); }

이 속성에 대해 엔터티가 지연 로딩 전략을 선언하더라도 Characteristic 엔터티 의 항목 속성을 열심히 로드합니다.

기존의 명명 된 엔티티 그래프를 참조하는 대신 엔티티 그래프를 인라인으로 정의 할 수 있으므로 편리합니다.

4. 테스트 케이스

이제 엔터티 그래프를 정의 했으므로이를 확인하는 테스트 사례를 만들어 보겠습니다.

@DataJpaTest @RunWith(SpringRunner.class) @Sql(scripts = "/entitygraph-data.sql") public class EntityGraphIntegrationTest { @Autowired private ItemRepository itemRepo; @Autowired private CharacteristicsRepository characteristicsRepo; @Test public void givenEntityGraph_whenCalled_shouldRetrunDefinedFields() { Item item = itemRepo.findByName("Table"); assertThat(item.getId()).isEqualTo(1L); } @Test public void givenAdhocEntityGraph_whenCalled_shouldRetrunDefinedFields() { Characteristic characteristic = characteristicsRepo.findByType("Rigid"); assertThat(characteristic.getId()).isEqualTo(1L); } }

첫 번째 테스트에서는 @NamedEntityGraph 주석을 사용하여 정의 된 엔티티 그래프를 사용합니다 .

Hibernate에 의해 생성 된 SQL을 보자 :

select item0_.id as id1_10_0_, characteri1_.id as id1_4_1_, item0_.name as name2_10_0_, characteri1_.item_id as item_id3_4_1_, characteri1_.type as type2_4_1_, characteri1_.item_id as item_id3_4_0__, characteri1_.id as id1_4_0__ from item item0_ left outer join characteristic characteri1_ on item0_.id=characteri1_.item_id where item0_.name=?

비교 를 위해 저장소에서 @EntityGraph 주석을 제거 하고 쿼리를 검사 해 보겠습니다 .

select item0_.id as id1_10_, item0_.name as name2_10_ from item item0_ where item0_.name=?

이러한 쿼리를 통해 @EntityGraph 주석 없이 생성 된 쿼리 Characteristic 엔터티의 속성을로드하지 않는 것을 명확하게 확인할 수 있습니다 . 결과적으로 Item 엔티티 만로드합니다 .

마지막으로 두 번째 테스트의 Hibernate 쿼리를 @EntityGraph 주석 과 비교해 보겠습니다 .

select characteri0_.id as id1_4_0_, item1_.id as id1_10_1_, characteri0_.item_id as item_id3_4_0_, characteri0_.type as type2_4_0_, item1_.name as name2_10_1_ from characteristic characteri0_ left outer join item item1_ on characteri0_.item_id=item1_.id where characteri0_.type=?

@EntityGraph 주석이 없는 쿼리 :

select characteri0_.id as id1_4_, characteri0_.item_id as item_id3_4_, characteri0_.type as type2_4_ from characteristic characteri0_ where characteri0_.type=?

5. 결론

이 튜토리얼에서 우리는 SpringData에서 JPA Entity Graphs를 사용하는 방법을 배웠습니다. SpringData를 사용하면 서로 다른 엔티티 그래프에 연결된 여러 저장소 메서드를 만들 수 있습니다 .

이 기사의 예제는 GitHub에서 사용할 수 있습니다.