JOIN 문으로 관련된 모든 테이블 데이터 가져옴
단, 쿼리 결과 예상을 못함
실제 클래스를 상속 받아 만들어진 것으로 사용자 입장에서는 진짜 객체랑 구분하지 않고 사용.
프로시 객체를 호출하면 실제 객체 메소드 호출
단, N+1 성능문제
Order 조회 -> 조회결과 2건
Member, Delivery 테이블 2번씩 조회, 총 5번 조회(최악의 경우)
단, 만약 같은 memer 혹은 delivery 라면 영속성 컨텍스트에서 가져오니까 최악 경우보다는 낫다
@GetMapping("/api/v2/simple-orders")
public List<SimpleOrderDto> ordersV2() {
List<Order> orders = orderRepository.findAllByString(new OrderSearch());
List<SimpleOrderDto> result = orders.stream()
.map(o -> new SimpleOrderDto(o)) // SimpleOrderDto::new
.collect(toList());
return result;
}
DTO
@Data
static class SimpleOrderDto {
private Long orderId;
private String name;
private LocalDateTime orderDate; //주문시간
private OrderStatus orderStatus;
private Address address;
public SimpleOrderDto(Order order) {
orderId = order.getId();
name = order.getMember().getName(); // 이 때 쿼리 나감
orderDate = order.getOrderDate();
orderStatus = order.getStatus();
address = order.getDelivery().getAddress(); // 이 때 쿼리 나감
}
}
지연로딩 쿼리 결과 N+1 문제
select
order0_.order_id as order_id1_6_,
order0_.delivery_id as delivery4_6_,
order0_.member_id as member_i5_6_,
order0_.order_date as order_da2_6_,
order0_.status as status3_6_
from
orders order0_
select
member0_.member_id as member_i1_4_0_,
member0_.name as name5_4_0_
from
member member0_
where
member0_.member_id=?
select
delivery0_.delivery_id as delivery1_2_0_,
delivery0_.city as city2_2_0_,
delivery0_.street as street3_2_0_,
from
delivery delivery0_
where
delivery0_.delivery_id=?
select
member0_.member_id as member_i1_4_0_,
member0_.name as name5_4_0_
from
member member0_
where
member0_.member_id=?
select
delivery0_.delivery_id as delivery1_2_0_,
delivery0_.city as city2_2_0_,
delivery0_.street as street3_2_0_,
from
delivery delivery0_
where
delivery0_.delivery_id=?
lazyLoading 시 연관된 엔티티를 조회할 때 지정된 size 만큼 SQL의 IN절을 사용해서 조회한다
spring.jpa.properties.hibernate.default_batch_fetch_size: 1000
select
order0_.order_id as order_id1_6_,
order0_.delivery_id as delivery4_6_,
order0_.member_id as member_i5_6_,
order0_.order_date as order_da2_6_,
order0_.status as status3_6_
from
orders order0_
inner join
member member1_
on order0_.member_id=member1_.member_id limit ?
Hibernate:
select
member0_.member_id as member_i1_4_0_,
member0_.city as city2_4_0_,
member0_.street as street3_4_0_,
member0_.zipcode as zipcode4_4_0_,
member0_.name as name5_4_0_
from
member member0_
where
member0_.member_id in (
?, ?
)
Hibernate:
select
delivery0_.delivery_id as delivery1_2_0_,
delivery0_.city as city2_2_0_,
delivery0_.street as street3_2_0_,
delivery0_.zipcode as zipcode4_2_0_,
delivery0_.status as status5_2_0_
from
delivery delivery0_
where
delivery0_.delivery_id in (
?, ?
)
연관된 테이블을 가져오지만, 프록시 객체가 아닌 실제 객체를 가져온다. 다만, 1:N 관계에서 가져올 떄 다음과 같은 데이터 뻥튀기 문제가 있어서 distinct로 다음과 같이 중복된 entity는 제거한다
public List<Order> findAllWithItem() {
return em.createQuery(
"select distinct o from Order o" +
" join fetch o.orderItems oi" +
" join fetch oi.item i", Order.class)
.getResultList();
}
Reference
김영한 강사님 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 강의