ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • spring boot querydsl study (4)
    카테고리 없음 2023. 4. 20. 09:53
    이번 시간에는 join에 대해서 알아보자. querydsl에서는 다음과 같은 조인을 지원한다. join inner join, left join, right join 일단 차례대로 한번씩 살펴보자.

    join

    QAccount account = QAccount.account;
    QOrder order = QOrder.order;
    return from(account)
      .join(account.orders, order)
      .fetch();
    
    join이라는 함수를 쓰면 join을 한다. join과 innerjoin의 차이점은 잘 모르겠다. 동일하게 작동하는 듯한데.. 쿼리를 보자.
    select 
      account0_.account_id as account_1_0_, 
      account0_.email as email2_0_, 
      account0_.name as name3_0_, 
      account0_.password as password4_0_ 
    from 
      account account0_ 
    inner join 
      orders orders1_ 
    on 
      account0_.account_id=orders1_.account_id
    
    쿼리에 나와 있듯이 innerjoin을 실행하였다. join과 innerjoin의 차이는 잘 모르니 패스 근데 on 메서드는 사용하지 않아도 자동으로 on은 자동으로 들어 가는 듯하다.

    inner join

    QAccount account = QAccount.account;
    QOrder order = QOrder.order;
    return from(account)
      .innerJoin(account.orders, order)
      .fetch();
    
    innerJoin이라는 함수를 쓰면 innerjoin을 한다. 쿼리를 보면 더 쉽게 알수 있을 거 같다.
    select 
      account0_.account_id as account_1_0_, 
      account0_.email as email2_0_, 
      account0_.name as name3_0_, 
      account0_.password as password4_0_ 
    from 
      account account0_ 
    inner join 
      orders orders1_ 
    on 
      account0_.account_id=orders1_.account_id
    
    쿼리에 나와 있듯이 innerjoin을 실행하였다. 마찬가지로 on메서드는 사용하지 않아도 자동으로 on은 들어 가는 듯하다.

    left join

    QAccount account = QAccount.account;
    QOrder order = QOrder.order;
    return from(account)
      .leftJoin(account.orders, order)
      .fetch();
    
    leftjoin도 마찬가지로 leftJoin을 사용하면 된다. 쿼리를 보면 다음과 같다.
    select 
      account0_.account_id as account_1_0_, 
      account0_.email as email2_0_, 
      account0_.name as name3_0_, 
      account0_.password as password4_0_ 
    from 
      account account0_ 
    left outer join 
      orders orders1_ 
    on 
      account0_.account_id=orders1_.account_id
    
    left outer join 을 사용하며 on 도 자동으로 사용된다.

    right join

    QAccount account = QAccount.account;
    QOrder order = QOrder.order;
    return from(account)
      .rightJoin(account.orders, order)
      .fetch();
    
    방식은 똑같다. rightJoin을 사용하면 된다. 마찬가지로 쿼리를 보자.
    select 
      account0_.account_id as account_1_0_, 
      account0_.email as email2_0_, 
      account0_.name as name3_0_, 
      account0_.password as password4_0_ 
    from 
      account account0_ 
    right outer join 
      orders orders1_ 
    on 
      account0_.account_id=orders1_.account_id
    
    아주 간단하게 사용 가능하다.

    fetch join

    fetch join은 원래 sql의 join을 말하는 것은 아니고 jpa의 성능 향상을 위해 만들어진 것이다. n+1이 발생했을 때 사용하면 적절하다. 사용법은 아주 간단하다.
    QOrder order = QOrder.order;
    QAccount account = QAccount.account;
    return from(order)
      .leftJoin(order.account, account).fetchJoin()
      .fetch();
    
    이 조인은 fetch join이라는 것만 명시 해주면 된다. 쿼리를 보면 다음과 같다.
    select 
      order0_.order_id as order_id1_3_0_, 
      account1_.account_id as account_1_0_1_, 
      order0_.account_id as account_3_3_0_, 
      order0_.order_date as order_da2_3_0_, 
      account1_.email as email2_0_1_, 
      account1_.name as name3_0_1_, 
      account1_.password as password4_0_1_ 
    from 
      orders order0_ 
    left outer join 
      account account1_ 
    on 
      order0_.account_id=account1_.account_id
    
    만약 fetch join을 사용하지 않고 해보자.
    QOrder order = QOrder.order;
    QAccount account = QAccount.account;
    return from(order)
      .leftJoin(order.account, account)
      .fetch();
    
    위와 같이 작성하면 쿼리는 다음과 같다.
    select 
      order0_.order_id as order_id1_3_, 
      order0_.account_id as account_3_3_, 
      order0_.order_date as order_da2_3_ 
    from 
      orders order0_ 
    left outer join 
      account account1_ 
    on 
      order0_.account_id=account1_.account_id
    
    
    select 
      account0_.account_id as account_1_0_0_, 
      account0_.email as email2_0_0_, 
      account0_.name as name3_0_0_, 
      account0_.password as password4_0_0_ 
    from 
      account account0_ 
    where 
      account0_.account_id=?
    
    
    select 
      account0_.account_id as account_1_0_0_, 
      account0_.email as email2_0_0_, 
      account0_.name as name3_0_0_, 
      account0_.password as password4_0_0_ 
    from 
      account account0_ 
    where 
      account0_.account_id=?
    
    
    select 
      account0_.account_id as account_1_0_0_, 
      account0_.email as email2_0_0_, 
      account0_.name as name3_0_0_, 
      account0_.password as password4_0_0_ 
    from 
      account account0_ 
    where 
      account0_.account_id=?
    
    
    이렇게 다음과 같이 한번 쿼리를 날렸지만 내부적으로는 n번의 쿼리를 더 날린셈이다. 이걸 보완하고자 fetchJoin이 만들어졌다. 또한 다음과 같은 코드가 있다고 하자.
    QAccount account = QAccount.account;
    QOrder order = QOrder.order;
    return from(account)
      .join(account.orders, order)
      .fetch();
    
    
    List<Account> accounts = accountRepository.findByInnerJoinOrders();
    for(Account account :accounts){
      System.out.println(account.getOrders());
    }
    
    위의 봤듯이 join하는 쿼리이다. 하지만 Account 에서 orders를 가져올 경우 에러가 발생한다. 그 에러는 바로 LazyInitializationException 이다. 물론 fetch가 LAZY로 되어 있을 때 이야기다. 하지만 fetchJoin을 사용하면 이 방법을 해결 할 수 있다.
    QAccount account = QAccount.account;
    QOrder order = QOrder.order;
    return from(account)
      .join(account.orders, order).fetchJoin()
      .fetch();
    
    그때 그때 적절하게 사용해야 한다. 무조건 fetchJoin이 좋은 것은 아니다. 굳이 필요 없는 데이터를 가져올 수도 있기 때문이다. Dto를 만들어도 되고 fetchJoin을 써도 되고 강제로 초기화를 해도 되고 방법은 많다. 그때그때 맞게 잘 사용하자. 우리는 좀 더 세부적으로 join에 대해서 알아봤다. 아직 갈길이 먼듯하다.

    댓글

Designed by Tistory.