요즘 회사 과제로 필터가 적용된 조회 기능을 구현하고 있다.
이를 위해 동적 쿼리를 사용한 게시물 조회 기능을 만들고자 QueryDSL을 사용해보려고 한다.
개인공부를 위해 작성한 글로 이 글에서는 JPQL과 QueryDSL을 비교하며 기본적인 문법부터 알아보겠습니다.
JPQL과 QueryDSL 비교
먼저, JPQL을 사용하여 username으로 데이터를 조회하는 예제를 보겠습니다.
@Test
void startJPQL() {
Member findMember =
em.createQuery("select m from Member m where m.username = :username", Member.class)
.setParameter("username", "member1")
.getSingleResult();
Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
}
이때 실행된 JPQL 쿼리는 다음과 같습니다:
select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
where
member0_.username=?
이번에는 QueryDSL을 사용하여 username으로 데이터를 조회하는 예제를 보겠습니다.
@Test
void startQuerydsl() {
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
QMember m = new QMember("m");
Member findMember = queryFactory
.select(m)
.from(m)
.where(m.username.eq("member1"))//파라미터 바인딩 처리
.fetchOne();
Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
}
• EntityManager로 JPAQueryFactory생성
• Querydsl은 JPQL빌더
• JPQL : 문자(실행 시점 오류), Querydsl : 코드 (컴파일 시점 오류)
• JPQL : 파라미터 바인딩 직접, Querydsl : 파라미터 바인딩 자동 처리
날아간 쿼리는 위의 JPQL에서와 같습니다.
select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
where
member0_.username=?
Q타입 인스턴스 사용 방법
QueryDSL에서 Q타입 인스턴스를 사용하는 방법은 세 가지가 있습니다.
1. new를 사용하는 방법
QMember m = new QMember("m");
Member findMember = queryFactory
.select(m)
.from(m)
.where(m.username.eq("member1"))
.fetchOne();
제일 권장하지 않는 방법이다.
2. static 필드 사용하기
QMember m = QMember.member;
Member findMember = queryFactory
.select(m)
.from(m)
.where(m.username.eq("member1"))
.fetchOne();
3. static 필드를 import하여 사용하는 방법(가장 권장되는 방법)
import static study.querydsl.entity.QMember.member;
Member findMember = queryFactory
.select(member)
.from(member)
.where(member.username.eq("member1"))
.fetchOne();
검색 조건 쿼리
검색 조건이 2개 이상일 때 and를 사용하여 조건을 추가할 수 있습니다.
@Test
void search1() {
Member findMember = queryFactory
.selectFrom(member)//요렇게 select + from 합치기 가능
.where(member.username.eq("member1")
.and(member.age.eq(10)))//and 또는 or로 체인걸기
.fetchOne();
Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
}
• 검색 조건은 .and(), .or() 를 메서드 체인으로 연결할 수 있다.
참고 : select 와 from을 위의 search1처럼 합칠 수 있음
Querydsl은 JPQL이 제공하는 모든 검색조건을 제공한다.
member.username.eq("member1") // username = 'member1'
member.username.ne("member1") // username != 'member1'
member.username.eq("member1").not() // username != 'member1'
member.username.isNotNull() // 이름이 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) // 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%") // like 검색
member.username.contains("member") // like ‘%member%’ 검색
member.username.startsWith("member") // like ‘member%’ 검색 ...
또한 아래와 같이 and조건을 파라미터로 처리할 수 있다.
@Test
void searchAndParam() {
Member findMember = queryFactory
.selectFrom(member)
.where(
//and조건 2개 파라미터
member.username.eq("member1"), member.age.eq(10)
)
.fetchOne();
Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
}
• where에 파라미터로 검색조건을 추가하면 AND조건이 추가된다.
• 이 경우 null값은 무시 -> 메서드 추출을 총해서 동적쿼리를 깔끔하게 만들 수 있다.
결과 조회
QueryDSL에서는 다양한 결과 조회 메서드를 제공합니다.
- fetch(): 리스트 조회, 데이터가 없으면 빈 리스트 반환
- fetchOne(): 단건 조회, 결과가 없으면 null, 둘 이상이면 NonUniqueResultException
- fetchFirst(): 첫 번째 결과 조회, limit(1).fetchOne()과 동일
예제를 통해 사용해보겠습니다.
@Test
void resultFetch() {
// 다수 조회
List<Member> fetch = queryFactory.selectFrom(member).fetch();
// 단건 조회
Member fetchOne = queryFactory.selectFrom(member)
.where(member.username.eq("member1"))
.fetchOne();
// 처음 한 건 조회
Member fetchFirst = queryFactory.selectFrom(member).fetchFirst();
}
수행된 쿼리는 다음과 같습니다:
// 리스트 조회
select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
// 단건 조회
select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
where
member0_.username=?
// 처음 한 건 조회
select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
limit ?
•참고 문헌 : 자바 ORM 표준 JPA 프로그래밍 / 김영한
'JPA' 카테고리의 다른 글
[JPA] QueryDSL에서 SQL Replace 함수 사용하기 (0) | 2024.07.21 |
---|---|
[QueryDSL] 중급 문법 (프로젝션, 동적 쿼리) (0) | 2024.06.20 |
자바 ORM 표준 JPA 기본편 - 영속성 전이 (0) | 2024.04.24 |
자바 ORM 표준 JPA 기본편 - 프록시와 연관관계 관리 (0) | 2024.04.17 |
자바 ORM 표준 JPA 기본편 - 고급매핑 (0) | 2024.04.12 |