본 글은 인프런의 김영한님 강의 실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
을 수강하며 기록한 필기 내용을 정리한 글입니다.
-> 인프런
-> 실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화 강의
@GetMapping("/simpleorder/v1")
public List<Order> ordersV1() {
List<Order> allOrders = orderService.findOrders(new OrderSearch());
return allOrders;
}
@JsonIgnore
어노테이션을 활용하면 끊어낼 수 있다....
@GetMapping("/simpleorder/v2")
public OrderResult<List<SimpleOrderDto>> ordersV2() {
List<SimpleOrderDto> orderDtos = orderService.findOrders(new OrderSearch())
.stream()
.map(SimpleOrderDto::new)
.collect(Collectors.toList());
return new OrderResult<>("주문 조회 완료", orderDtos);
}
@Data
static class SimpleOrderDto {
private Long orderId;
private String name;
private LocalDateTime orderDate;
private OrderStatus orderStatus;
private Address address;
public SimpleOrderDto(Order order) {
this.orderId = order.getId();
this.name = order.getMember().getName();
this.orderDate = order.getOrderDate();
this.orderStatus = order.getStatus();
this.address = order.getDelivery().getAddress();
}
}
@Data
@AllArgsConstructor
static class OrderResult<T> {
private String message;
private T data;
}
...
{
"message": "주문 조회 완료",
"data": [
{
"orderId": 4,
"name": "userA",
"orderDate": "2023-06-29T19:19:31.615095",
"orderStatus": "ORDER",
"address": {
"city": "서울",
"street": "1",
"zipcode": "1111"
}
},
{
"orderId": 11,
"name": "userB",
"orderDate": "2023-06-29T19:19:31.644563",
"orderStatus": "ORDER",
"address": {
"city": "진주",
"street": "2",
"zipcode": "2222"
}
}
]
}
orderDtos
에 담기게 되고, Controller 단에서 다음 과정을 거친다. List<SimpleOrderDto> orderDtos = orderService.findOrders(new OrderSearch())
.stream()
.map(SimpleOrderDto::new)
.collect(Collectors.toList());
SimpleOrderDto
의 생성자를 자세히 보면 public SimpleOrderDto(Order order) {
this.orderId = order.getId();
this.name = order.getMember().getName(); // LAZY 초기화
this.orderDate = order.getOrderDate();
this.orderStatus = order.getStatus();
this.address = order.getDelivery().getAddress(); // LAZY 초기화
@Override
public List<Order> findAll(OrderSearch orderSearch) {
return em.createQuery("SELECT o FROM Order o JOIN FETCH o.member JOIN FETCH o.delivery", Order.class)
.getResultList();
}
SELECT o FROM Order o JOIN FETCH o.member JOIN FETCH o.delivery
select
order0_.order_id as order_id1_9_0_,
member1_.member_id as member_i1_6_1_,
delivery2_.delivery_id as delivery1_3_2_,
order0_.created_at as created_2_9_0_,
order0_.modified_at as modified3_9_0_,
order0_.delivery_id as delivery6_9_0_,
order0_.member_id as member_i7_9_0_,
order0_.orderdate as orderdat4_9_0_,
order0_.status as status5_9_0_,
member1_.created_at as created_2_6_1_,
member1_.modified_at as modified3_6_1_,
member1_.city as city4_6_1_,
member1_.street as street5_6_1_,
member1_.zipcode as zipcode6_6_1_,
member1_.name as name7_6_1_,
delivery2_.created_at as created_2_3_2_,
delivery2_.modified_at as modified3_3_2_,
delivery2_.city as city4_3_2_,
delivery2_.street as street5_3_2_,
delivery2_.zipcode as zipcode6_3_2_,
delivery2_.status as status7_3_2_
from
orders order0_
inner join
member member1_
on order0_.member_id=member1_.member_id
inner join
delivery delivery2_
on order0_.delivery_id=delivery2_.delivery_id
SimpleOrderQueryDto
파일을 생성하고 다음 내용으로 구성한다.@Data
@AllArgsConstructor
public class SimpleOrderQueryDto {
private Long orderId;
private String name;
private LocalDateTime orderDate;
private OrderStatus orderStatus;
private Address address;
}
OrderRepositoryImpl
에서 다음과 같이 활용한다. @Override
public List<SimpleOrderQueryDto> findOrderDtos(OrderSearch orderSearch) {
return em.createQuery("SELECT "
+ "new jpabook.jpashop.domain.order.dto.SimpleOrderQueryDto(o.id, m.name, o.orderDate, o.status, d.address)"
+ " FROM Order o JOIN o.member m JOIN o.delivery d", SimpleOrderQueryDto.class)
.getResultList();
}
OrderServiceImpl
에서도 다음과 같이 반환해주고, @Override
public List<SimpleOrderQueryDto> findOrderDtos(OrderSearch orderSearch) {
return orderRepository.findOrderDtos(orderSearch);
}
OrderSmpleApiController
에서 활용해준다. @GetMapping("/simpleorder/v4")
public OrderResult<List<SimpleOrderQueryDto>> orderV4() {
return new OrderResult<>("주문 조회 완료", orderService.findOrderDtos(new OrderSearch()));
}
SELECT
new jpabook.jpashop.domain.order.dto.SimpleOrderQueryDto(o.id, m.name, o.orderDate, o.status, d.address)
FROM Order o JOIN o.member m JOIN o.delivery d
SimpleOrderQueryDto
의 생성자를 활용해서 조회한 데이터들을 곧바로 넣어서 반환하는 것을 확인할 수 있다.⇒ ⭐ 따라서 V3 방식으로 개발했을 때 얻을 수 있는 장점들(재사용성, Repository 독립 등)과 V4 방식으로 개발했을 때 얻을 수 있는 장점들(컬럼 개수 절감을 통한 성능 개선)을 비교해서 상황에 맞추어 적절히 활용해야 한다. ⭐
@Repository
@RequiredArgsConstructor
public class OrderSimpleQueryRepositoryImpl implements OrderSimpleQueryRepository {
private final EntityManager em;
@Override
public List<SimpleOrderQueryDto> findOrderDtos(OrderSearch orderSearch) {
return em.createQuery("SELECT "
+ "new jpabook.jpashop.domain.order.dao.dtorepository.SimpleOrderQueryDto(o.id, m.name, o.orderDate, o.status, d.address)"
+ " FROM Order o JOIN o.member m JOIN o.delivery d", SimpleOrderQueryDto.class)
.getResultList();
}
}
<쿼리 방식 선택 권장 순서>