일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 강화학습
- 백준 장학금
- SpringSecurity
- AVL트리
- posix
- 연결리스트
- HTTP
- jpa n+1 문제
- 운영체제
- 프로세스
- 스케줄링
- 연결리스트 종류
- Kruskal
- 최대 힙
- 자료구조
- 멀티프로세서
- 점근적 표기법
- 알고리즘
- JPA
- heapq
- 완전이진트리
- JVM
- 백준장학금
- python
- spring
- 엔티티 그래프
- MSA
- 이분탐색이란
- 최소힙
- 힙트리
- Today
- Total
KKanging
[JPA] 엔티티 그래프 본문
엔티티 그래프를 사용하는 이유는 ? ???
연관된 엔티티를 같이 조회할 때 사용하는 방법들
- fetch 옵션 (즉시 로딩)
- fetch join
fetch 옵션은 사용하면 N+1 쿼리가 날라가기도 하고 원하지 않을때 연관된 엔티티가 같이 조회될 수 있음
fetch join 은 좋은 해결책 중 하나지만 페치 조인을 사용하면 다음과 같이 JPQL을 중복해서 작성하는 경우가 많다.
// case 1
select o from Order o
where o.status = ?
// case 2
select o from Order o
join fetch o.member
where o.status = ?
// case 3
select o from Order o
join fetch o.orderItems
where o.status = ?
3가지 JPQL 모두 주문을 조회하는 JPQL이지만 함께 조회할 엔티티에 따라서 다른 JPQL을 사용해야 한다.
이것은 JPQL 이 데이터를 조회하는 기능뿐만 아니라 연관된 엔티티를 함께 조회하는 기능도 제공하기 때문이다.
이는 엔티티 그래프를 사용해서 연관된 엔티티를 함께 조회하면 되고 JPQL은 데이터를 조회하는 기능만 수행할 수 있다.
Named 엔티티 그래프
@NamedEntityGraph(name = "Order.withMember", attributeNodes = {
@NamedAttributeNode("member")
})
@Entity
@Table(name = "ORDERS")
public class Order {
@Id @GeneratedValue
private Long id;
@ManyToOne(fetch = FetchTYpe.LAZY, optional = false)
@JoinCloumn(name = "MEMBER_ID")
private Member member;
...
}
위와 같이 선언하면 엔티티 그래프를 사용할 수 있다.
EntityGraph graph = em.getEntityGraph("Order.withMember");
Map hints = new HashMap();
hints.put("javax.persistence.fetchgraph", graph);
Order order = em.find(Order.class, orderId, hints);
사용할 때는 em.getEntityGraph("Order.withMember"); 로 hint를 가지고 오고 find 에 사용해야한다.
subgraph
Order → OrderItem → Item까지 함께 조회해보자. Order → OrderItem은 Order가 관리하는 필드지만 OrderItem → Item은 Order가 관리하는 필드가 아니다.
@NamedEntityGraph(name = "Order.withAll", attributeNodes = {
@NamedAttributeNode("member"),
@NamedAttributeNode(value = "orderItems", subgraph = "orderItems")
},
subgraphs = @NamedSubgraph(name = "orderItems", attributeNodes = {
@NamedAttributeNode("item")
})
)
@Entity
@Table(name = "ORDERS")
public class Order {
@Id @GeneratedValue
private Long id;
@ManyToOne(fetch = FetchTYpe.LAZY, optional = false)
@JoinCloumn(name = "MEMBER_ID")
private Member member;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<OrderItem>();
...
}
@Entity
public class OrderItem {
@Id @GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ITEM_ID")
private Item item;
...
}
JPQL에서 엔티티 그래프 사용
List<Order> resultList =
em.createQuery("select o from Order o where o.id = :orderId", Order.class)
.setParameter("orderId", orderId)
.setHint("javax.persistence.fetchgraph", em.getEntityGraph("Order.withAll"))
.getResultList();
동적 엔티티 그래프
엔티티 그래프를 동적으로 구성하려면 createEntityGraph() 메소드를 사용하면 된다.
EntityGraph<Order> graph = em.createEntityGraph(Order.class);
graph.addAttributeNodes("member");
Subgraph<OrderItem> orderItems = graph.addSubgraph("orderItems");
orderItems.addAttributeNodes("item");
Map hints = new HashMap();
hints.put("javax.persistence.fetchgraph", graph);
Order order = em.find(Order.class, orderId, hints);
이미 로딩된 데이터는?
Order order = em.find(Order.class, orderId); // 이미 조회
hints.put("javax.persistence.fetchgraph", em.getEntityGraph("Order.withMember"));
Order order2 = em.find(Order.class, orderId, hints);
영속성 컨텍스트에 해당 엔티티가 이미 로딩되어 있으면 엔티티 그래프가 적용되지 않는다.(아직 초기화되지 않은 프록시에는 엔티티 그래프가 적용된다.)
fetchgraph, loadgraph의 차이
fetchgraph는 엔티티 그래프에 선택한 속성만 함께 조회한다. 반면에 loadgraph 속성은 엔티티 그래프에 선택한 속성뿐만 아니라 글로벌 fetch 모드가 FetchType.EAGER로 설정된 연관관계도 포함해서 함께 조회한다.
Spring Data JPA 에서 엔티티 그래프 적용하는 법
@EntityGraph(attributePaths = {"fetch join 할 객체의 필드명"}
// Entity Graph
@Override
@EntityGraph(attributePaths = {"team"}) // 객체의 필드명
List<Member> findAll();
// JPQL에 Entity Graph추가(fetch join)
@EntityGraph(attributePaths = {"team"})
@Query("select m from Member m")
List<Member> findMemberEntityGraph();
// 메서드 이름으로 쿼리 생성 + EntityGraph추가(fetch join)
@EntityGraph(attributePaths = {"team"})
List<Member> findEntityGraphByUsername(@Param("username") String username);
@NamedEntityGraph + @EntityGraph
@NamedEntityGraph(name = "Member.all", attributeNodes = @NamedAttributeNode("team"))
public class Member{
...
}
// Member 객체에 선언한 @NamedEntityGraph를 사용
@EntityGraph("Member.all")
List<Member> findEntityGraphByUsername(@Param("username") String username);
요약
엔티티 그래프를 사용하면 다음과 같은 JPQL에도 fetch join을 적용할 수 있다!
select o from Order o
where o.status = ?
아마 spring data jpa도 위와 같은 간단한 where 문에 fetch join 을 적용하는 거 같다.
참고자료
- >자바 ORM 표준 JPA 프로그래밍 - 김영한
'백엔드 > JPA' 카테고리의 다른 글
[JPA] JPA N+1 문제 발생 원인과 해결 방법 (0) | 2024.05.14 |
---|---|
[JPA] Context 주기와 트랜잭션 주기 그리고 OSIV (0) | 2024.05.08 |