강의

멘토링

커뮤니티

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

인프런21님의 프로필 이미지
인프런21

작성한 질문수

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

간단한 주문 조회 V3: 엔티티를 DTO로 변환 - 페치 조인 최적화

Inner Join VS Left Join

작성

·

1.1K

0

Inner Join 이 발생하려면, @ManyToOne 에서 @JoinColumn 의 nullable =false 이거나, 

@ManyToOne.optional=false 로 설정해야한다고 하셨는데요, 이번 강의에서는 이러한 설정이 없었음에도 iniiner join 으로 사용되는 이유가 궁금합니다. 

감사합니다. 

답변 7

0

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

안녕하세요. 인프런21님^^

강의에서 제공하는 코드보다는 깔끔하게 새로 예제를 하나 만드시고, 다음 3가지 경우를 테스트해보시겠어요?

1. em.find()

2. JPQL로 inner join

3. JPQL로 left join

그러면 원하는 답을 찾으실 수 있을거에요.

테스트 해보시고 질문 남겨주시면 추가로 도움을 드릴게요.

감사합니다.

0

인프런21님의 프로필 이미지
인프런21
질문자

 음..find 는 아니었고요,

아래 코드였습니다.

문득 사용중인 코드가 다를수도 있겠다는 생각이 드네요;;

실전! 스프링 부트와 JPA 활용1을 듣지않고 

실전! 스프링 부트와 JPA 활용2를 바로 듣는 중이고요

주신 강의자료에는 OrderReposotiry 코드가 없어서 

https://github.com/holyeye/jpabook/blob/master/ch11-jpa-shop/src/main/java/jpabook/jpashop/repository/OrderRepository.java 코드로 실습하고 있습니다.

제가 강의에서 사용하신 코드를 확인해볼수 있을까요?

public List<Order> findAll(OrderSearch orderSearch) {

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
Root<Order> o = cq.from(Order.class);

List<Predicate> criteria = new ArrayList<Predicate>();

//주문 상태 검색
if (orderSearch.getOrderStatus() != null) {
Predicate status = cb.equal(o.get("status"), orderSearch.getOrderStatus());
criteria.add(status);
}

//회원 이름 검색
if (StringUtils.hasText(orderSearch.getMemberName())) {
Join<Order, Member> m = o.join("member", JoinType.INNER); //회원과 조인
Predicate name = cb.like(m.<String>get("name"), "%" + orderSearch.getMemberName() + "%");
criteria.add(name);
}

cq.where(cb.and(criteria.toArray(new Predicate[criteria.size()])));
TypedQuery<Order> query = em.createQuery(cq).setMaxResults(1000); //최대 검색 1000 건으로 제한
return query.getResultList();
}

감사합니다. 

0

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

네 혹시 실행을 어떻게 하셨는지요?

아마 find로만 실행을 해보셨을 건데요.

동일한 조건으로 다음 3가지를 테스트해보시겠어요?

1. em.find()

2. JPQL로 inner join

3. JPQL로 left join 

그러면 뭔가 답을 찾으실 수 있을거에요^^

0

인프런21님의 프로필 이미지
인프런21
질문자

네, 감사합니다. 제가 테스트 진행한 내역은 아래와 같습니다. :)

아래 코드는 Delivery 엔티티의 일부인데요, 이 중 order 에 FetchType.LAZY 를 붙이지 않을 경우,  @ManyToOne.optional=false 와 @JoinColumn.nullable =false 여부와 관계 없이 항상 LEFT JOIN 이 발생합니다. 

(FetchType.LAZY 를 붙일 경우, 정상적으로 Delivery 단건 수행이 진행됩니다. )

책에서는 @ManyToOne.optional=false 와 @JoinColumn.nullable =false  어노테이션으로 제어가 가능한 것으로 이해했었는데요, 제가 잘못 이해한 부분이 있는걸까요?


@JsonIgnore
@OneToOne(mappedBy = "delivery", fetch = FetchType.LAZY)
private Order order;

실제 사용된 코드는 아래와 같습니다 .


@Entity
@Table(name = "ORDERS")
@Getter
@Setter
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", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<OrderItem>();

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "DELIVERY_ID", nullable = false)
// @JoinColumn(name = "DELIVERY_ID")
// @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
// @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
// @JoinColumn(name = "DELIVERY_ID")
private Delivery delivery;

private LocalDateTime orderDate;

@Enumerated(EnumType.STRING)
private OrderStatus status; // [ORDER, CANCEL]
// 이하 생략...

 Delivery 엔티티 코드는 아래와 같습니다. 

@Entity
public class Delivery {

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

@JsonIgnore
@OneToOne(mappedBy = "delivery", fetch = FetchType.LAZY)
private Order order;

@Embedded
private Address address;

@Enumerated(EnumType.STRING)
private DeliveryStatus status; //ENUM [READY(준비), COMP(배송)]
// 이하 생략...

이렇게 실행할 경우 , 항상 LEFT JOIN 이 발생합니다. 

감사합니다.

0

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

네 잘 찾아주셔서 감사합니다^^

제가 바로 답을 드릴 수도 있지만, 코드로 직접 짜보면서 각각의 차이를 느껴보아야 진정한 배움이 있습니다.

그래서 앞서 질문 드린 것 처럼 1,2번을 예제 코드로 만들어서 각각 실행해보시겠어요?

그리고 1번은 어떤 문맥에서 어떤 경우에만 적용되는지 코드로 한번 확인해보시겠어요?

그럼 답변 기다릴게요^^

0

인프런21님의 프로필 이미지
인프런21
질문자

안녕하세요 강사님 :)

1) @ManyToOne 에서 @JoinColumn 의 nullable =false 이거나,  @ManyToOne.optional=false 로 설정해야한다고 하셨는데요 ==> 이 부분은 저술하신 책 298 페이지의 내용입니다

2) 이번 강의에서는 이러한 설정이 없었음에도 iniiner join 으로 사용되는 이유가 궁금합니다. 

==> 이번 강의 v2, v3 의 내용입니다. 

JPA 경험이 거의 없이 짧은 시간에 많은 공부를 하려다보니 오히려 헷갈리기도 하는것 같네요 ㅎㅎ

많은 조언을 부탁드립니다. 감사합니다.

0

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

안녕하세요. 인프런21님

Inner Join 이 발생하려면, @ManyToOne 에서 @JoinColumn 의 nullable =false 이거나,  @ManyToOne.optional=false 로 설정해야한다고 하셨는데요. -> 이 부분은 혹시 어떤 경우를 말하는 걸까요? 대략 감이 오기는 하는데 정확한 답을 위해서 다시 물어보아요. 예제 코드를 작성하고 실행한 다음에 그 결과를 보여주세요.

이번 강의에서는 이러한 설정이 없었음에도 iniiner join 으로 사용되는 이유가 궁금합니다. 

-> 이 부분도 어떤 경우에 어떤 코드를 실행해서 그런걸까요? 예제 코드를 작성하고 실행한 다음에 그 결과를 보여주세요.

그럼 답변 기다릴게요^^

인프런21님의 프로필 이미지
인프런21

작성한 질문수

질문하기