QueryDSL
특징
자바 코드로 query를 보낼 수 있다. -> 컴파일 과정에서 문법 오류를 발견할 수 있다.
세팅
build.gradle
plugins와 queryDSL이 자동으로 생성하는 디렉토리 경로
plugins {
id 'org.springframework.boot' version '2.2.2.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE' //querydsl 추가
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
id 'java'
}
//querydsl 추가 시작
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main.java.srcDir querydslDir
}
configurations {
querydsl.extendsFrom compileClasspath
}
compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}
//querydsl 추가 끝
plugins에 querydsl과 버전이 추가되어있는 것과
querydsl에서 제공하는 기능을 사용하기 위해 필요한 설정에 대해 이런게 있구나 정도로 넘어간다.
generated 생성하기
Gradle in side tab -> Tasks -> other -> compileQuerydsl
기본 활용
// EntityManager em;
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
QMember m = new QMember("m");
Member findMember = queryFactory
.select(m)
.from(m)
.where(m.username.eq("member1"))
.fetchOne();
JPAQueryFactory은 멀티 쓰레딩에 안전하게 설계되었으므로 공유되어 사용해도 좋다.
동시성 문제는 EntityManager에 달려있고 transaction마다 별도의 영속성 컨텍스트를 제공하기 때문에 안전하다.
참고
where의 여러 인수로 predicate를 넘기면 and로 연결한다.
Q-Type 활용
QMember qMember = new QMember("m"); // alias 직접 지정
QMember qMember = QMember.member; // 내부에서 생성한 기본 인스턴스 사용
위의 QMember.member는 QMember의 public static 멤버 변수이다.
따라서 변수로 초기화하여 사용할 필요없이 QMember.member
로 사용가능하다.
역시 static 변수 member의 타입은 QMember이다.
참고로 내부에서 생성했다함은 QMember에 new QMember("member1");
처럼 생성된 것을 말한다.
즉, query의 alias로 member1
이 사용된다는 의미이다.
일반적으로 QMember.member 처럼 static 변수로 사용하는 것을 권장한다.
그리고 사실 alias를 위한 variable을 지정했을 때의 장점을 모르겠다.
검색 조건
member.username.eq("정상수") // username = '정상수'
member.username.ne("정상수") // username != '정상수'
member.username.eq("정상수").not() // username != "정상수"
member.username.isNotNull()
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%' 검색
참고
like 연산자는 와일드카드를 이용하여 검색할 수 있다.
와일드 카드에는 %, _
가 있다.
결과 조회
List<Member> fetch = queryFactory
.selectFrom(member)
.fetch();
// 단건
// 결과가 없으면 null
// 결과가 둘 이상이면 NonUniqueResultException
Member findMember1 = queryFactory
.selectFrom(member)
.fetchOne();
// 처음 한 건 조회
// limit(1).fetchOne()
Member findMember2 = queryFactory
.selectFrom(member)
.fetchFirst();
// 페이징에서 사용
// 성능이 중요하면 쿼리를 나누는 것이 좋을 수도
QueryResults<Member> results = queryFactory
.selectFrom(member)
.fetchResults();
// count 쿼리로 변경
long count = queryFactory
.selectFrom(member)
.fetchCount();
fetchResults()에 대해서 자세히 알아보자.
QueryResults<Member> results = queryFactory
.selectFrom(member)
.fetchResults();
results.getTotal();
List<Member> content = results.getResults();
위 코드를 실행하면 query가 두 번 실행된다는 특징이 있다.
total count를 얻는 query와 질의 query가 따로 나간다.
count query
select query
참고
위 /* 주석으로 덮인 select는 JPQL, 아닌 것은 sql statement
# application.property
# JPQL을 보는 방법
spring.jpa.properties.hibernate.use_sql_comments: true
정렬
List<Member> result = queryFactory
.selectFrom(member)
.where(member.age.eq(100))
.orderBy(member.age.desc(), member.username.asc().nullsLast())
.fetch();
주의해서 봐야할 것은
where에 필요한 BooleanExpression(Predicate)는 .eq method
orderBy에 필요한 OrderSpecifier(Comparable) 로 표현했다.
'스프링' 카테고리의 다른 글
QueryDSL 볶아먹기 (0) | 2023.10.22 |
---|---|
QueryDSL 다져먹기 (0) | 2023.10.21 |
테스트 코드 정의와 이점, 왜 해야 할까? 그리고 무엇을 해야 할까? (0) | 2023.07.08 |
JPA란? (0) | 2023.07.06 |
서블릿이 뭔데? (0) | 2023.06.07 |