1. 설치
- build.gradle
...
dependencies {
...
//Querydsl 추가
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
}
def generated = 'src/main/generated'
// querydsl QClass 파일 생성 위치를 지정
tasks.withType(JavaCompile) {
options.getGeneratedSourceOutputDirectory().set(file(generated))
}
// java source set 에 querydsl QClass 위치 추가
sourceSets {
main.java.srcDirs += [ generated ]
}
// gradle clean 시에 QClass 디렉토리 삭제
clean {
delete file(generated)
}
- Gradle/build/build 실행
- 위에 설정한src/main/generated/sources 밑에 Q{Entity} 클래스들 생성 확인

2. Repository 구조

(→ Academy 라는 Repo example)
- 기본적으로 3가지 Repo 파일을 생성한다.

- CustomRepositoryImpl : QueryDsl를 사용할 custom repo 구현체, CustomRepository 상속
- QReservation r = QReservation.reservation; → src/main/generated/sources에 확인
@RequiredArgsConstructor
public class CustomReservationRepositoryImpl implements CustomReservationRepository {
private final JPAQueryFactory queryFactory;
public List<Reservation> findReservations() {
QReservation r = QReservation.reservation;
return queryFactory.selectFrom(r).where(r.customerId.eq("tom")).fetch();
}
}
- CustomRepository
public interface CustomReservationRepository {
public List<Reservation> findReservations();
}
- Repository: JpaRepository<Entity, PK_TYPE>, CustomRepository 상속
public interface ReservationRepository extends JpaRepository<Reservation, Long>, CustomReservationRepository {
List<Reservation> findByCustomerId(String customerId);
Reservation findByReservationPaymentFilm(String reservationPaymentFilm);
List<Reservation> findFirst2ByCustomerId(String customerId);
}
3. JPAQuery Config 빈 등록
- Querydsl를 사용하려면 JPAQueryFactory가 필요
- 일일히 주입받기 귀찮으므로 bean으로 등록하여 생성자 주입을 받는다.
- @PersistenceContext : DataSourceConfiguration에서 생성한 EntityManager를 주입.
@Configuration
public class QueryDslConfig {
private static JPAQueryFactory jpaQueryFactory;
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
4. 테스트
@SpringBootTest
@Slf4j
@RequiredArgsConstructor
public class QueryDslTest {
@Autowired
ReservationRepository reservationRepository;
@Test
void QueryDSLTest() {
List<Reservation> reservations = reservationRepository.findReservations();
for(Reservation r: reservations) {
log.info("{}, {}, {}, {}",r.getReservationPaymentId(), r.getCustomerId(),
r.getReservationPaymentScheduleId(), r.getReservationPaymentFilm());
}
}
}
5. 문법
- 결과 조회
fetch() : 리스트 조회, 데이터 없으면 빈 리스트 반환(null 아니다)
fetchOne() : 단 건 조회, 결과가 없으면 null, 결과가 둘 이상이면 예외 발생
fetchFirst() : limit(1).fetchOne() 과 같다.
- 정렬
desc() : 내림차순
asc() : 올림차순
nullsLast() : null 데이터 순서 부여(마지막)
nullsFirst() : null 데이터 순서 부여(처음)
- 페이징
offset(long offset) : 쿼리 결과에 대한 오프셋을 정의, 0부터 시작
limit(long limit) : 쿼리 결과에 대한 제한/최대 결과를 정의
- 집합
count() : 카운트 sum() : 합 avg() : 평균 max() : 최대 min() : 최소
- 그룹화
groupby() : 그룹화/집계 having() : 그룹화/집계용 필터
- 조인
join(), innerJoin() : 내부 조인(inner join) leftJoin() : left 외부 조인(left outer join) rightJoin() : right 외부 조인(right outer join)
- 조인 예제 - Customer(customerName), Reservation(customId)
public List<Reservation> CustomsReservation(String customName) {
QReservation r = QReservation.reservation;
QCustomer c = QCustomer.customer;
return queryFactory.selectFrom(r).
join(c).on(r.customerId.eq(c.customerName)).
where(c.customerName.eq(customName)).
fetch();
}
- 서브 쿼리
- com.querydsl.jpa.JPAExpressions
- int()
- select()
Share article