JPQL과 QueryDSL
- Querydsl은 JPQL 빌더 역할을 한다.
- 차이점
- JPQL
- 문자열로 작성하기 때문에 실행 시점에 오류를 찾아낸다.
- 직접 파라미터 바인딩을 해줘야 한다.
- Querydsl
- 코드로 작성하기 때문에 컴파일 시점 오류를 찾아낸다.
- 자동으로 파라미터를 바인딩 해준다.
맛보기
JPQL
QueryDSL
EntityManager
로 JPAQueryFactory
를 생성한다.
JPAQueryFactory를 공통 필드로 사용하기
- JPAQueryFactory를 필드로 제공할 때 동시성 문제는 걱정하지 않아도 된다.
- JPAQueryFactory를 생성할 때 제공하는 EntityManager가 해결해준다.
- 스프링 프레임워크는 여러 쓰레드에서 동시에 같은 EntityManager에 접근해도, 트랜잭션 마다 별도의 영속성 컨텍스트를 제공한다.
Q-Type 클래스 인스턴스를 사용하는 방법
- 기본적으로는 인스턴스 방식을 사용한다.
- 별칭은 서브 쿼리를 작성할 때 주로 사용된다.
- 기본 인스턴스를 static import해서 사용할 수도 있다.
기본 검색
- select 메소드와 from 메소드에서 사용되는 Q-Type을 경우에는 selectFrom 메소드를 사용할 수 있다.
조건 검색
where(Predicate... o)
메소드를 활용해서 조회 조건을 추가할 수 있다.Predicate
클래스를 통해서 조건을 나타낸다.- 만약에 검색 조건 메소드에 파라미터로 들어간 값이 null이라면 해당 조건은 무시된다.
and()
나 or()
를 통해서 체인을 걸 수 도 있다.Predicate
를 쉼표로 구분하면 각 조건문끼리는 AND로 연결된다.
WHERE A AND (B OR C)
같은 복합 조건도 사용할 수 있다.
검색 조건 메소드
역할 | 메소드명 | 사용 예시 | SQL |
---|
같은지 비교 | eq | member.username.eq(“member1”) | username = ‘member1’ |
같지 않은지 비교 | ne | member.username.ne(“member1”) | username != ‘member1’ |
부정 연산 | not | member.username.eq(“member1”).not() | username != ‘member1’ |
NOT NULL 체크 | isNotNull | member.username.isNotNull() | username is not null |
포함 여부 확인 | in | member.age.in(10, 20) | age in (10,20) |
미포함 여부 확인 | notIn | member.age.notIn(10, 20) | age not in (10, 20) |
범위 검색 | between | member.age.between(10, 30) | between 10, 30 |
XX 이상 | goe | member.age.goe(30) | age >= 30 |
XX 초과 | gt | member.age.gt(30) | age > 30 |
XX 이하 | loe | member.age.loe(30) | age <= 30 |
XX 미만 | lt | member.age.lt(30) | age < 30 |
패턴에 의한 부분 일치 검색 | like | member.username.like(“member%”) | username like ‘member%’ |
부분 일치 검색 | contains | member.username.contains(“member”) | username like ‘%member%’ |
지정 문자열로 시작하는 부분 검색 | startsWith | member.username.startsWith(“member”) | username like ‘member%’ |
지정 문자열로 끝는 부분 검색 | endsWith | member.username.endsWith(“member”) | username like ‘%member’ |
- 이외에도 수많은 검색 조건 메소드가 존재한다.
중복 제거
distinct()
메소드를 통해 중복을 제거할 수 있다.
결과 조회
fetch()
- 리스트 조회
- 결과가 없으면 빈 리스트를 반환한다.
fetchOne()
- 단 건 조회
- 결과가 없으면 null을 반환한다.
- 결과가 둘 이상이면 예외를 발생시킨다.
fetchFirst()
limit(1).fetchOne()
을 한 것과 같은 결과를 반환한다.
fetchResults()
- 페이징 정보를 포함한 결과를 반환한다.
- 총 개수를 조회하는 쿼리도 함께 실행된다.
- deprecated
fetchCount()
- 총 개수를 조회하는 쿼리로 변환해서 실행한다.
- deprecated
정렬
orderBy(OrderSpecifier<?>... o)
메소드를 통해 정렬한다.- orderBy 메소드 안에 정렬 방식을 나열하면 된다.
- 종류
- asc()
- desc()
- nullsFirst()
- nullLast()
페이징
offset(long offset)
- 데이터를 읽어들이기 시작하는 위치를 지정한다.
- 기본 위치는 0부터 시작한다.
limit(long limit)
fetchResults()
를 통해 페이징 정보를 가져올 수 있다.- 다만 deprecated 상태라서 추후 경우에 따라서 따로 처리를 해줘야 할 수도 있다.
그룹 함수
- 기본적인 그룹 함수
- 필드.count()
- 필드.sum()
- 필드.avg()
- 필드.max()
- 필드.min()
- 이외에도 다양한 그룹 함수를 제공한다.
- 그룹 함수를 사용할 때 Tuple을 사용하는 경우가 많다.
group by와 having
groupBy(Expression<?>... o)
메소드를 통해 그룹화를 할 수 있다.- groupBy 메소드 안에 그룹화할 대상을 나열하면 된다.
having(Predicate... o)
메소드를 통해 그룹화 조건을 지정할 수 있다.- having 메소드 안에 그룹화 조건을 나열하면 된다.
조인 - 기본 조인
join(EntityPath<P> target, Path<P> alias)
메소드를 통해 기본 조인을 실행한다.- target에는 조인 대상을 지정한다.
- alias에는 별칭으로 사용할 Q-Type을 지정하면 된다.
- SQL처럼 ON절을 직접 추가하지 않아도 미리 정의한 연관관계를 통해서 키 값을 매핑하는 ON절을 자동으로 작성해준다.
조인 - on절
on(Predicate... conditions)
메소드를 통해 조인 조건을 추가할 수 있다.- on 메소드 안에 조인 조건을 나열하면 된다.
조인 - 페치 조인
fetchJoin()
메소드를 통해 페치 조인을 실행할 수 있다.
서브 쿼리
- 기본적으로 Q-Type 클래스는 인스턴스를 사용하는 방법이 두 가지가 있다.
QMember qMember = new QMember("m"); //별칭 직접 지정
QMember qMember = QMember.member; //기본 인스턴스 사용
- 서브 쿼리를 사용할 때는 별칭 방식을 사용해야 한다.
- JPAExpressions를 통해 서브 쿼리를 작성한다.
- 서브 쿼리를 사용하는 방식 자체는 메인 쿼리와 별차이가 없다.
Case문
- 복잡한 방식
- 복잡한 변수를 사용할 때는 변수로 따로 선언해서 사용하는 것이 좋다.
상수 사용하기
- 상수를 표현해야 하는 경우에 사용한다.
Expressions.constant(T value)
메소드 안에 상수로 표현할 값을 명시하면 된다.
문자 더하기
concat(String str)
메소드를 통해 문자열을 합칠 수 있다.
출처