[QueryDSL] 3. 기본 문법(1) Q-Type, 검색 조건 쿼리, 결과 조회, 정렬, 페이징, 집합, 조인(페치 조인, on절, 기본 조인)

2022. 10. 7. 16:56인프런/실전! QueryDSL

728x90

 

1️⃣ JPQL vs Querydsl 

 

테스트 기본 코드

QuerydslBasicTest

-> 테스트를 위해서 계속 같은 데이터를 입력하고 하기 귀찮으니까 

@BeforeEach 어노테이션을 통해서 미리 애플리케이션 로딩될 때 member와 Team 데이터 몇개를 넣어두도록 했다. 

 

 

Querydsl vs JPQL

JPQL

-> username이 member1인 member를 조회하는 예제이다. 

그리고 jpql을 실행해서 조회해온 findMember의 이름이 member1인지 테스트 

(-> jpql과 sql이 같이 나오고 있음)

 

QueryDSL

-> JPQL과 예제는 같다. 

EntityManager로 JpaQueryFactory를 생성해준다. 

QueryDSL도 뭐 특별한 기능이 있는 것이 아니라 JPQL 빌더역할을 하는 것 뿐이다. 

 

🥰

JPQL: 문자(실행 시점에 오류), QueryDSL: 코드 (컴파일 시점에 오류)

JPQL: 파라미터 바인딩 직접, QueryDSL : 파라미터 바인딩 자동 처리 

 

 

JPAQueryFactory를 필드로 제공할 수 도 있는데 그러면 동시성 문제는 어떻게 될까? 

동시성 문제는 JPAQueryFactory를 생성할 때 제공하는 EntityManager(em)에 달려있다.

스프링 프레임워크는 여러 쓰레드에서 동시에 같은 EntityManager에 접근해도, 트랜잭션 마다 별도의 영속성 컨텍스트를 제공하기 때문에, 동시성 문제는 걱정하지 않아도 된다. 

 

 

2️⃣ 기본 Q-Type 활용 

Q클래스 인스턴스를 사용하는 2가지 방법

QMember qMember = new QMember("m"); -> 별칭 직접 지정 

QMember qMember = QMember.member; -> 기본 인스턴스 사용 

 

기본 인스턴스를 static import 와 함께 사용

 

🙂 참고: 같은 테이블을 조인해야 하는 경우가 아니라면 기본 인스턴스를 사용하자~~

 

실행되는 JPQL 확인하는 방법 

application.yml

spring.jpa.properties.hibernate.use_sql_comments : true 

 

-> 그럼 이런 식으로 sql과  jpql을 함께 볼 수 있다. 

 

 

3️⃣ 검색 조건 쿼리 

- 기본 검색 쿼리

-> 회원의 이름이 member1 이고, 나이는 10살인 회원을 조회하는 예제이다. 

이때 검색 조건은 and(), or()로 메서드 체인으로 연결할 수 있다. 

 

🙂 참고: select, from을 selectFrom으로 합칠 수 있음 

 

 

- JPQL이 제공하는 모든 검색 조건 제공

 

- AND 조건을 파라미터로 처리

where() 에 파라미터로 검색 조건을 추가하면 AND 조건이 추가됨 

이 경우에는 NULL 값은 무시된다. -> 이게 엄청난 장점!! 메서드 추출을 활용해서 동적 쿼리를 깔끔하게 만들 수 있음. 

 

 

4️⃣ 결과 조회 

fetch() : 리스트 조회, 데이터 없으면 빈 리스트 반환 

fetchOne() : 단 건 조회 

  - 결과가 없으면 null 

  - 결과가 둘 이상이면 com.querydsl.core.NonUniqueResultException 

fetchFirst() : limit(1).fetchOne() 

fetchResults() : 페이징 정보 포함, total count 쿼리 추가 실행

fetchCount() : count 쿼리로 변경해서 count 수 조회 

 

-> fetchResults와 fetchCount는 근데 deprecated 됐다...!! 

https://velog.io/@nestour95/QueryDsl-fetchResults%EA%B0%80-deprecated-%EB%90%9C-%EC%9D%B4%EC%9C%A0

 

QueryDsl) fetchResults()가 deprecated 된 이유

QueryDsl로 페이징 쿼리를 작성하는데 .fetchResults()가 deprecated 되었다고 표시되었길래 찾아보았다.보면 queryDsl과 JPQL 간의 차이? 같은게 있는 것 같다.queryDsl의 fetchResult의 경우 count를 하기위해선 cou

velog.io

 

-> List 조회 

 

-> 단 건 조회 

 

-> 처음 한 건 조회 

 

-> 페이징에서 사용 

 

 

 

5️⃣ 정렬

정렬 예제를 위해서 member를 추가로 입력해줬다.

그리고 정렬을 하려면 orderBy() 메서드에 desc() , asc() 일반 내림차순, 올림차순을 사용할 수 있다. 

nullsLast(), nullsFirst()은 null 데이터 순서 부여로 null 값은 맨 뒤로 정렬할 것인지, 맨 앞으로 정렬할 것이지 이다. 

 

 

 

6️⃣ 페이징

- 조회 건수 제한 

offset은 기본은 0부터 시작이다. 근데 여기서는 1부터 시작으로 지정해줬고, limit2로 지정해서 최대 2건 조회하도록 했다. 

 

 

- 전체 조회 수가 필요하다면?

fetchResults()를 사용하면 전체 totalCount도 얻을 수있는데 이건 count 쿼리가 같이 나가기 때문에 성능상 주의해야 한다.

 

참고

: 실무에서 페이징 쿼리를 작성할 때, 데이터를 조회하는 쿼리는 여러 테이블을 조인해야 하지만, 

count 쿼리는 조인이 필요 없는 경우도 있다. 

그런데 이렇게 자동화된 count 쿼리는 원본 쿼리와 같이 모두 조인을 해버리기 때문에 성능이 안나올 수 있다. 

따라서 count 쿼리에는 조인이 필요없는 경우에 성능 최적화가 필요하다면 count 전용 쿼리를 별도로 작성해야 한다. 

 

 

7️⃣ 집합

- 집합 함수 

count -> 회원 수 

sum -> 나이 합 

avg -> 평균 나이 

max -> 최대 나이 

min -> 최소 나이 

 

QueryDSL은 JPQL이 제공하는 모든 집합 함수를 제공한다. 

tuple은 프로젝션과 결과반환에서 설명한다. 

 

 

- GroupBy 사용

 팀별로 팀 이름과 평균 연령을 구하는 예제이다. 

groupBy를 사용해서 팀 별로 그룹화 할 수 있다. 

만약 그룹화된 결과에 대해서 결과를 제한하고 싶다면 having을 사용해주면 된다. 

 

 

8️⃣ 조인 - 기본 조인 

: 조인의 기본 문법은 첫 번째 파라미터에 조인 대상을 지정하고, 두번째 파라미터에 별칭 alias으로 사용할 Q 타입을 지정하면 된다. 

join( 조인 대상, 별칭으로 사용할 Q타입) 

 

- 기본 조인 

member와 team을 (내부)조인하고, 이때 team 이름이 teamA인 결과를 조회하는 예제이다. 

result 결과는 member1과 member2이다. 

join(), innerJoin() : 내부 조인 (inner join) 

leftJoin() : left 외부 조인 (left outer join)

rightJoin() : right 외부 조인 (right outer join)

JPQL의 on과 성능 최적화를 위한 fetch 조인 제공 

 

 

- 세타 조인

: 연관관계가 필요 없는 조인 

예제를 억지로 만들어낸 것으로, 만약에 회원 이름과 team 이름이 같은 경우를 조회하는 예제이다. 

세타조인은 from 절에 여러 엔티티를 선택해주면 된다. 

 

근데 세타 조인은 원래 외부 조인이 불가능했는데, 조인 on절을 사용하면 외부 조인이 가능해졌다!! 

 

 

9️⃣ 조인 - ON절 

ON절을 활용한 조인 

1. 조인 대상 필터링
2. 연관관계 없는 엔티티 외부 조인 

 

1. 조인 대상 필터링

ex) 회원과 팀을 조인하면서 팀 이름이 teamA인 팀만 조회, 회원은 모두 조회 

-> left outer join이기 때문에 team 이름이 teamA가 아니면 null로 member를 가져옴 

 

참고

on절을 활용해서 조인 대상을 필터링할 때, 외부 조인이 아니라 내부 조인을 사용하면, 

where 절에서 필터링 하는 것과 기능이 동일하다. 

따라서 on 절을 활용한 조인 대상 필터링을 사용할 때, 내부 조인이면 익숙한 where 절로 해결하고, 

정말 외부 조인이 필요한 경우에만 이 기능을 사용하도록..!!!

 

 

2. 연관관계 없는 엔티티 외부 조인 (세타 조인에서 외부 조인 가능하도록) 

예) 회원의 이름과 팀의 이름이 같은 대상 외부 조인 

하이버네이트 5.1 부터 on을 사용해서 서로 관계가 없는 필드로 외부 조인하는 기능이 추가되었다. (물론 내부 조인도 가능) 

 

주의: 문법을 잘 봐야 한다!! leftJoin() 부분에 일반 조인과 다르게 엔티티 하나만 들어간다. 

일반조인: leftJoin(member.team, team)

on 조인: from(member).leftJoin(team).on(xxx) 

 

 

🔟 조인 - 페치 조인 

페치 조인은 SQL에서 제공하는 기능은 아니다. SQL 조인을 활용해서 연관된 엔티티를 SQL 한번에 조회하는 기능이다. 

주로 성능 최적화에 사용하는 방법 

 

- 페치 조인 미적용

: 지연 로딩으로 Member, Team SQL 각각 실행 

Member와 Team이 지연로딩 전략이기 때문에 Member만 조회해 온 것을 확인할 수 있다. 

 

 

- 페치 조인 적용

: 즉시 로딩으로 Member, Team SQL 쿼리 조인으로 한번에 조회 

사용 방법 -> join(), leftJoin() 등 조인 기능 뒤에 fetchJoin() 이라고 추가하면 된다. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90