인프런 커뮤니티 질문&답변

코린코린님의 프로필 이미지

작성한 질문수

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

간단한 주문 조회 V1: 엔티티를 직접 노출

OrderItems까지 같이 조회되는 이유가 궁금합니다!

작성

·

512

2

안녕하세요

항상 좋은 답변 남겨주셔서 감사합니다

OrderItems까지 같이 조회되는 이유가 궁금해서 글을 적게 되었습니다.

 

 

@GetMapping("/api/v1/simple-orders")
public List<Order> ordersV1() {
List<Order> orders = orderService.findOrders(new OrderSearch());
orders.forEach(order ->
{
order.getMember().getName();
order.getDelivery().getStatus();
});
return orders;
}

V1 컨트롤러는 다음과 같습니다.

 

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "orders")
public class Order {

@Id
@GeneratedValue
@Column(name = "order_id")
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;

@OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.ALL) // order가 만들어지면 orderItem이 만들어지기 때문에 영속성 전이한다.
private List<OrderItem> orderItems = new ArrayList<>();

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Delivery delivery;

private LocalDateTime orderDate;

@Enumerated(EnumType.STRING)
private OrderStatus status;

ORDER는 다음과 같습니다.

 

@Entity
@Getter
@Setter
public class OrderItem {

@Id
@GeneratedValue
@Column(name = "orderitem_id")
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "item_id")
private Item item;

@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;

private int orderPrice;
private int count;

ORDER_ITEM은 다음과 같습니다.

 

 

여기서 V1 컨트롤러를 통해서 쿼리를 날리면, 뒤늦게 Lazy Loading을 통해서 Order_Item들이 프록시 초기화가 되는 것처럼 나갑니다. 

그런데 실제로는 프록시가 초기화도 되어있지 않습니다.

 

정리하면 이렇습니다

1. Order_Items는 Lazy Loading 설정이 되어있고,  프록시 객체를 강제 초기화 하는 과정도 없습니다. 그런데 왜 select 쿼리가 나가게 되는 것인지 알려주실 수 있으실까요?

 

2. orderItem에 대한 select 쿼리가 나갔음에도 불구하고 실제 응답에 있는 값은 null입니다. 이 경우는 어떻게 이해를 해야할까요?

 

항상 좋은 답변 주셔서 감사합니다! 

답변 2

1

시간이 지나 해결하셨을거 같은데 관련해서 답변이 있는거 같습니다 저도 이것보고 이해가 갔습니다.

https://inflearn.com/questions/270886

와...말씀대로 getTotalPrice()메서드에 @JsonIgnore 달아주니 쿼리가 안나가네요!👍

0

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. ...님

전체 프로젝트를 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.

구글 드라이브 업로드 방법은 다음을 참고해주세요.

https://bit.ly/3fX6ygx

 

주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요

 

추가로 다음 내용도 코멘트 부탁드립니다.

1. 실행 방법을 알려주세요.

2. 어떻게 문제를 확인할 수 있는지 자세한 설명을 남겨주세요.

감사합니다.

코린코린님의 프로필 이미지
코린코린
질문자

안녕하세요!

답글 달아주셔서 너무 감사합니다.

 

자답 가능할 것 같습니다! 

@OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.ALL) // order가 만들어지면 orderItem이 만들어지기 때문에 영속성 전이한다.
private List<OrderItem> orderItems = new ArrayList<>();

말씀하신 내용 하나하나 확인해보니 요 부분이 문제였던 것 같습니다

OrderItem이 Order에 영속성 전이가 되어서, Order가 select 될 때 OrderItems가 같이 Select 되게 된 것 같습니다.

 

감사합니다! 

김영한님의 프로필 이미지
김영한
지식공유자

스스로 잘 해결하셨습니다^^

@안상혁 cascade 옵션 때문은 아닌 거 같습니다. 실제로 cascade 설정을 하지 않아도 동일하게 마지막에 orderItems 를 가져오는 쿼리를 날리는 것을 확인할 수 있습니다.

 

debugging 해보니까 응답을 만들기 위해 serialize 를 하는 과정에서 결국 쿼리가 날아가는 거 같던데, 왜 굳이 그런 동작이 이뤄지는지는 아직 잘 모르겠습니다.

저도 같은 내용때문에 고민중입니다ㅜㅜㅜorder 와 조인하는 member, delivery 는 proxy 객체로 넘어가는것을 볼수 있는데 orderItem 은 왜 lazy 강제 초기화 하는 것처럼 쿼리가 날라가는 건지 모르겠습니다. 어딜 이해못하고 있는건지..jpa어렵습니다...

image

 return em.createQuery(
                        "select o from Order o " +
                                 "join o.member m "
                                 "join o.delivery d " 
                )
                .getResultList();