JPQL vs Querydsl
Before:: 원천 데이터 셋업
Code
JPQL vs Querydsl
Code
JPAQueryFactory 를 필드로 뺄 수도 있다.
Code
참고: JPAQueryFactory를 필드로 제공하면 동시성 문제(Multi Threading)은 어떻게 될까?
→ 스프링 프레임워크는 여러 쓰레드에서 동시에 같은 EntityManager에 접근해도, 트랜잭션 마다 별도의 영속성 컨텍스트를 제공하기 때문에,
동시성 문제는 일어나지 않는다.
기본 Q-Type 활용
위의 Querydsl 예제에서는 Q클래스의 인스턴스를 사용할 때 new QMember("m") 와 같이 new 를 통해 별칭을 직접 지정해줬지만,
Querydsl 에서 제공하는 기본 인스턴스를 사용하는게 더 간편하다.
QMember qMember = new QMember("M"); // 별칭 직접 지정
QMember qMember = QMember.member; //기본 인스턴스 사용
Java
복사
•
Q클래스를 static-import 해주면 member 도 바로 사용할 수 있다.
import static study.querydsl.entity.QMember.*;
@Test
public void startQuerydsl3(){
Member findMember = queryFactory.selectFrom(member).where(member.id.eq(1L).fetchOne();
assertThat(findMember.getId)).isEqualTo(1L);
}
Java
복사
검색 조건 쿼리
기본 검색 쿼리
Code
AND 조건을 메서드 체인 말고 파라미터로 처리할 수도 있습니다.
Code
JPQL이 제공하는 모든 검색 조건을 제공합니다.
•
member.username.eq("a") : username = 'a'
•
member.username.ne("a") : username ≠ 'a'
•
member.username.eq("a").not() : username ≠ 'a'
•
member.username.isNotNull() : username is not null
•
member.age.in(10,20) : age in (10,20)
•
member.age.notIn(10,20) : age not in(10,20)
•
member.age.between(10,30) : age between 10, 30
•
member.age.goe(30) : age ≥ 30
•
member.age.gt(30) : age > 30
•
member.age.loe(30) : age ≤ 30
•
member.age.lt(30) : age < 30
•
member.username.like("member%") : username like 'member%'
•
member.username.contains("member') : username like '%member%'
•
member.username.startsWith("member") : like 'member%'
•
.... 등등
결과 조회
→ queryFactory 를 통해 생성한 쿼리들(queryFactory.select(member).from(member).where(member.id.eq(1L))...) )의 결과를 반환하는 함수들에 대해 소개한다.
•
fetch() : 리스트 조회, 데이터 없으면 빈 리스트 반환
•
fetchOne() : 단 건 조회
◦
결과가 없으면: null
◦
결과가 둘 이상이면: com.querydsl.core.NonUniqueResultException
•
fetchFirst() : limit(1).fetchOne() 과 같다.
•
fetchResults() : 페이징 정보 포함, total count 쿼리 추가 실행
•
fetchCount() :count 쿼리로 변경해서 count 수 조회
테스트 코드 작성 및 검증
Code
정렬
Querydsl 에서는 정렬(Sort)용 메서드 역시 제공된다. → .orderBy(인스턴스명.기준필드.정렬기준.(nullsLast()|nullsFirst()))
정렬 코드 작성 및 검수
Code
페이징
조회 건수 제한
Code
전체 조회 수가 필요한 경우
Code
집합
JPQL이 제공하는 모든 집합 함수를 Querydsl 에서 제공한다.
집함 함수 코드
Code
Group By 사용 → 팀의 이름과 각 팀의 평균 연령을 구해라.
Code
조인 - 기본 조인
→ Querydsl 에서는 JOIN 함수도 역시 제공된다.
•
join() , innerJoin() : 내부 조인(inner join)
•
leftJoin() : left 외부 조인(left outer join)
•
rightJoin() : right 외부 조인(right outer join)
•
JPQL의 on 과 성능 최적화를 위한 fetch 조인 제공
그렇다면 연관관계가 없는 엔티티간의 조인은 어떻게 하는가? → 세타 조인
Code
조인 - on절
ON 절을 활용한 조인(JPA 2.1부터 지원)
•
조인 대상 필터링
•
연관관계 없는 엔티티 외부 조인
1. 조인 대상 필터링
회원과 팀을 조인하면서, 팀 이름이 teamA인 팀만 조인, 회원은 모두 조회
Code
2. 연관관계 없는 엔티티 외부 조인
회원의 이름과 팀의 이름이 같은 대상 외부 조인
Code
조인 - 페치 조인
페치 조인은 SQL 자체적으로 제공하는 기능은 아니고 JPA에서 SQL조인을 활용해서 연관된 엔티티를 SQL 한 번에 조회해 가져오는 기능입니다. 성능 최적화를 위해 엔티티 연관관계에서 모든 로딩전략을 지연로딩(fetch = fetchType.LAZA)으로 설정하는데, 페치조인을 사용하면, getter 호출시마다 쿼리를 수행하는 것을 막을 수 있습니다.
Before:: 페치 조인 미적용
→ 지연로딩으로 Member, Team SQL 쿼리 각각 실행
Code
After::페치 조인 적용
→ 즉시로딩으로 Member, Team SQL 쿼리 조인으로 한 번에 조회
Code
서브 쿼리
→ com.querydsl.jpa.JPAExpressions 를 사용하여 서브쿼리 사용이 가능하다.
서브쿼리 eq 사용
Code
서브쿼리 goe 사용
Code
서브쿼리 여러 건 처리 in절 사용
Code
서브쿼리 select 절에서 사용sele
Code
from절의 서브쿼리 한계
→ JPA JPQL 서브쿼리의 한계점으로 from절의 서브쿼리(인라인 뷰)는 지원하지 않습니다.
JPQL 쿼리 빌더인 Querydsl 역시 같은 이유로 지원하지 않습니다.
하이버네이트 구현체를 사용하면 select절의 서브쿼리는 지원합니다. Querydsl도 하이버네이트 구현체를 사용하면 select 절 서브쿼리를 지원합니다.
from절의 서브쿼리 한계돌파 방안
1.
서브쿼리 → JOIN 으로 변경한다. (가능한 상황도 있고, 불가능한 상황도 있다.)
2.
애플리케이션에서 쿼리를 2번 분리해서 실행한다.
3.
nativeSQL 을 사용한다.
Case 문
Querydsl 에서 select, 조건절(where)에서 사용 가능합니다.
단순한 조건
Code
복잡한 조건
Code
상수, 문자 더하기
상수가 필요하다면 Expressions.constant(xxx) 사용
Code
참고: 위와 같이 최적화가 가능하면 SQL에 constant 값을 넘기지 않는다. 상수를 더하는 것 처럼 최적화가 어려우면 SQL에 constant값을 넘긴다
문자 더하기 concat
Code
참고: member.age.stringValue() : 문자가 아닌 다른타입(ex: int, float..)들을 문자로 변환해준다. 이 방법은 ENUM을 처리할 때도 자주 사용한다.