1. JPQL vs Querydsl
✅JPQL 조회, Querydsl 조회 비교
package study.querydsl;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import study.querydsl.entity.Member;
import study.querydsl.entity.Team;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static study.querydsl.entity.QMember.member;
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Autowired
EntityManager em;
JPAQueryFactory queryFactory; //필드로 만들어도됨
@BeforeEach
public void before(){
queryFactory = new JPAQueryFactory(em);
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
em.persist(teamA);
em.persist(teamB);
Member member1 = new Member("member1", 10, teamA);
Member member2 = new Member("member2", 20, teamA);
Member member3 = new Member("member3", 30, teamB);
Member member4 = new Member("member4", 40, teamB);
em.persist(member1);
em.persist(member2);
em.persist(member3);
em.persist(member4);
}
@Test
public void startJPQL(){
//member1 찾기
String qlString =
"select m from Member m " +
"where m.username = :username"; //런타임 시점에 오류확인
Member findMember = em.createQuery(qlString, Member.class)
.setParameter("username", "member1") //파라미터바인딩 직접 입력
.getSingleResult();
assertThat(findMember.getUsername()).isEqualTo("member1");
}
@Test
public void startQuerydsl(){
Member findMember = queryFactory //컴파일 시점에 오류확인
.select(member)
.from(member)
.where(member.username.eq("member1")) //파라미터바인딩 자동
.fetchOne(); //단일레코드 조회
assertThat(findMember.getUsername()).isEqualTo("member1");
}
}
- Querydsl은 EntityManager로 JPAQueryFactory 생성해줘야한다.
JPAQueryFactory는 필드로 빼줘도 된다.
✔️JPQL과 Querydsl 특징
JPQL | Querydsl | |
쿼리 작성 | 문자열 | Java 코드 |
오류 확인 시점 | 런타임(실행 시점) | 컴파일(코드 작성 시점) |
파라미터 바인딩 | 수동 | 자동 |
2. Q-Type 활용
Querydsl을 사용하는 프로젝트에서 엔티티 클래스를 만들면 자동으로 Q-Type 클래스를 생성한다.
Querydsl로 쿼리를 작성할 때는 Q-Type 클래스를 사용한다.
QMember qMember = new QMember("m"); //별칭 직접 지정
QMember qMember = QMember.member; //기본 인스턴스 사용
Q-Type 인스턴스를 통해 쿼리를 작성해야하니 인스턴스를 생성해줘야한다.
위 코드처럼 직접 써도 되지만 자동 생성된 Q클래스에 이미 member 인스턴스가 만들어져있다.
import static study.querydsl.entity.QMember.*;
기본 인스턴스를 static import를 해주면 더 깔끔하게 코드를 작성할 수 있다.
💡같은 테이블을 조인해야 하는 경우가 아니면 기본 인스턴스를 사용하는 것이 좋다.
@Test
public void search(){
Member findMember = queryFactory
.selectFrom(member)
.where(member.username.eq("member1")
.and(member.age.eq(10)))
.fetchOne();
assertThat(findMember.getUsername()).isEqualTo("member1");
}
이 테스트 코드에서 member가 Q클래스 인스턴스다.
3. 검색 문법
▪️ selectFrom()
select(member).from(member) 처럼 select와 from뒤에 오는 것이 같다면, selectFrom(member)로 합칠 수 있다.
▪️ eq()
eq()는 ' = ' 이고
eq()로 파라미터 바인딩을 자동으로 할 수 있다.
eq()로는 null 비교를 할 수 없기 때문에 null인지 아닌지 판단할 때는 isNull(), isNotNull()을 쓴다.
▪️ ne()
ne()는 ' != ' 이다. 참고로, ne는 not equal의 줄임말이다.
ne()는 eq().not()으로 쓸 수도 있다.
▪️ goe()
'>=' greater or equal의 줄임말이다.
member.age.goe(30) 는 age >= 30 를 의미.
▪️ gt()
'>' greater than의 줄임말이다. '크다'
member.age.gt(30) 는 age > 30 를 의미.
▪️ loe()
'<=' less or equal의 줄임말이다. '작거나 같다'
member.age.loe(30) 는 age <= 30 를 의미.
▪️ lt()
'<' less than의 줄임말이다. '작다'
member.age.lt(30) 는 age < 30 를 의미.
▪️ between( , )
between(10,30)은 10 ≤ 값 ≤ 30 을 의미한다.
10과 30도 포함된다는 것을 헷갈리지 말자.
▪️ 조건 추가 and
@Test
public void search(){
Member findMember = queryFactory
.selectFrom(member)
.where(member.username.eq("member1")
.and(member.age.eq(10)))
.fetchOne();
assertThat(findMember.getUsername()).isEqualTo("member1");
}
@Test
public void searchAndParam(){
Member findMember = queryFactory
.selectFrom(member)
.where(member.username.eq("member1"),
member.age.eq(10))
.fetchOne();
assertThat(findMember.getUsername()).isEqualTo("member1");
}
첫번째 테스트처럼 where뒤에 and()로 조건을 추가해줄 수 있고, 두번째 테스트처럼 and조건을 where()에 쉼표로 이어서 조건을 추가해줄 수 있다.
▪️ like()
기존 SQL 문법에 있는 like처럼 사용한다.
like("member%")는 member로 시작하는 문자열을 찾는 것이다.
▪️ contains()
like("%member%")와 같다. 문자열 위치 상관없이 포함하는 것을 찾는 것이다.
▪️ startsWith()
like("member%")와 같다. member로 시작하는 문자열을 찾는다.
4. 결과 조회
List<Member> fetch = queryFactory
.selectFrom(member)
.fetch();
Member fetchOne = queryFactory
.selectFrom(member)
.fetchOne();
Member fetchFirst = queryFactory
.selectFrom(member)
.fetchFirst();
select, from, where등을 사용해서 검색 쿼리를 다 작성하고 리스트로 결과를 받을 때 결과조회 메서드를 사용한다.
안붙이면 타입이 JPAQuery<Member>가 된다.
▪️ fetch()
리스트 조회를 할 수 있고 데이터가 없으면 빈 리스트를 반환한다.
▪️ fetchOne()
단 건 조회가 확실할 때, fetchOne()을 사용한다.
결과가 둘 이상이면 NonUniqueResultException 예외가 발생한다.
▪️ fetchFirst()
첫번째 결과 행을 가져온다.
limit(1).fetchOne()과 같다.
limit()은 쿼리 결과의 최대 행의 수를 제한하는 메서드다.
🤔강의를 보면 fetchResults()와 fetchCount()가 나오는데, 이 두 메서드는 향후 지원되지 않을 메서드라서
다른 쿼리로 대체해야한다.
김영한님 강의 수강자는 강의자료 섹션8을 보면 된다. 여기에 최신 버전에 맞춘 설명이 나온다.
fetchResult(), fetchCount()를 대체하는 법은 다음 포스팅에서 다룰 예정이다.
'인프런 김영한 강의 정리 > 실전! Querydsl' 카테고리의 다른 글
[Querydsl] 기본 문법(4) - Case문 (0) | 2024.08.09 |
---|---|
[Querydsl]기본 문법(3) - 서브 쿼리 (0) | 2024.08.09 |
[Querydsl] 기본 문법(2) - 조인 (0) | 2024.08.08 |
[Querydsl] fetchResults(), fetchCount() 대체하기 (0) | 2024.08.07 |
프로젝트 환경설정 (SpringBoot 3.x 버전), Querydsl 설정 (0) | 2024.07.27 |