이번 시간에는 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에 대해서 알아봤다. 아직 갈길이 먼듯하다.