Spring발행일 2024. 8. 23.원본 https://blog.naver.com/jword_/223553162595 ↗

자바(JAVA) Query DSL 사용하기

자바(JAVA) Query DSL 사용하기 — #querydsl #javaquerydsl #자바querydsl #개발자의도구들 🚨📝 📖 📒✏️💡🔍 AI스쿨 msa기...

#Spring#Naver Blog

#querydsl #javaquerydsl #자바querydsl #개발자의도구들

🚨📝 📖 📒✏️💡🔍

​

AI스쿨 msa기반 java 백엔드 코스 중에 공부한 내용을 작성하였습니다

\* 현재 Spring 프로젝트를 진행 중입니다. 전체적인 목차를 보시려면 여기를 눌러주세요.

이미지

​

복습하고 가요

이전글에서 Spring JPA query method까지 적용을 다 해봤었습니다. 복잡한 로직도 Spring JPA와 JPQL을 함께 사용하면 천하 무적일 것 처럼 느껴지는데요. 하지만, JPQL을 쓰는 것에 몇 가지 문제점이 있습니다.

​

JPQL의 문제점

String jpql = "SELECT u FROM User u WHERE u.name = :name";List<User> users = em.createQuery(jpql, User.class) .setParameter("name", "John") .getResultList();

보시다 싶이 JPQL은 기본적으로 문자열(String) 기반으로 쿼리를 작성합니다. 위의 JPQL의 쿼리에 user.name 속성을 where절로 비교하고 있는데요. 실제로 user에 name속성이 없다고 해도 쿼리는 실행됩니다. 그럼 실제 DB에서는 당연히 쿼리 오류를 낼 것이고, 결국 프로그램에 오류가 발생하게 될 것입니다.

이런 오류를 컴파일 시점에서 바로 찾을 수 있도록 하려면 QueryDsl을 사용할 수 있습니다.

Query DSL

Query Domain Specific Language는 Java에서 Query 작성시 type을 미리 체크하여 컴파일 시점에 Query 오류를 발견할 수 있도록 도와줍니다.

​

QBoardEntity board = QBoardEntity.board;List<BoardEntity> boards = queryFactory .selectFrom(Board) .where(board.title.eq("some Title")) // 올바른 타입 : String , 전달한 타입 : String .fetch();​List<BoardEntity> boards = queryFactory .selectFrom(Board) .where(board.title.eq(123)) // 올바른 타입 : String , 전달한 타입 : INT -> err .fetch();
✏️그 외 장점들​ 1. 동적쿼리 생성에 유리( Criteria API 보다 가독성이 좋음) 2. 코드 가독성이 좋다. 3. JPA뿐 아니라 여러 환경에서도 사용이 가능하다. 4. 복잡한 쿼리 작성을 지원해준다.

환경설정

build.gradle(for JAVA)

implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"annotationProcessor "jakarta.annotation:jakarta.annotation-api"annotationProcessor "jakarta.persistence:jakarta.persistence-api"

+ Kotlin version

plugins { // for query DSL kotlin("kapt") version "1.9.10"}​​// query DSL setting - Q classkapt{ includeCompileClasspath = false arguments { arg("querydsl.entityAccessors", "true") arg("querydsl.useKotlinClass", "true") }}​// query DSLdependencies { implementation ("com.querydsl:querydsl-jpa:5.0.0:jakarta") kapt ("com.querydsl:querydsl-apt:5.0.0:jakarta") kapt ("jakarta.annotation:jakarta.annotation-api") kapt ("jakarta.persistence:jakarta.persistence-api")}

​

​

cmd

./gradlew clean build

이미지

​

한번 돌려주면 위 경로에 QEntity가 생성됩니다.

​

Syntax(Class & Method)

주요 class와 그 class의 method에 대해서 정리해 보았습니다. Criteria Api처럼 이해하시면 편합니다.

​

JPAQueryFactory

QueryDSL에서 쿼리를 생성하고 실행하는 중심 클래스입니다.

JPAQueryFactory queryFactory = new JPAQueryFactory(entityManger);

쿼리를 직접 생성하는 곳이기 떄문에 query와 관련된 다양한 method들을 지원합니다.

​select(...) : 특정 필드나 엔티티 선택(반환 값(필드))selectFrom(...) : 엔티티를 선택하는 기붠 쿼리를 시작 (select랑 from이 같음)from(...) : 쿼리에서 사용할 엔티티 지정 (쿼리 적용할 놈) where(...) : 쿼리 조건을 지정fetch() : 쿼리를 실행하고 결과를 리스트로 반환fetchOne() : 쿼리 실행 후 단일 결과 반환fetchFirst() : 쿼리 실행 후 첫 번째 결과 반환fetchCount() : 쿼리의 결과 수 반환 ​

​

QEntity

QEntity는 앞에서도 언급했듯이, EntityClass를 기반으로 자동으로 생성됩니다.

private final QBoardEntity board = QBoardEntity.boardEntity;

BooleanBuilder

동적 쿼리를 만들어야 하는 상황에서 사용할 수 있습니다.

BooleanBuilder builder = new BooleanBuilder();if (condtion1) { builder.and(board.writer.eq("John Doe"));} ​if (condition2) { builder.and(board.title.contains("Spring"));}

주로 조건을 추가하는 method들을 지원합니다.

and(...) : 기존 조건에 AND 조건 추가or(...) : 기존 조건에 OR 조건 추가not(...) 기존 조건을 부정한다.hasValue() 조건이 존재하는지 확인

​

Repostiory

QueryDsl을 사용하기 위해서는 Repository를 추가해주어야 합니다. 이는JPA(Hibernate)에서 생성하는 방법과 동일하게 구현해 줄 수 있습니다.

@RequiredArgsConstructor@Repositorypublic class BoardQueryDslRepositoryImpl implements BoardQueryDslRepository{ private final JPAQueryFactory queryFactory; private final QBoardEntity board = QBoardEntity.boardEntity;​ @Override public List<BoardEntity> findByWriterLikeDsl(String writer) { return queryFactory .selectFrom(board) .where(board.writer.like(writer)) // 조건 추가 .fetch(); // List로 불러오기 }}

​

총 정리

  • 컴파일 시점의 Entity 필드 체크를 위해 Query DSL을 사용하면 좋다. (JPQL은 런타임에 체크됨)
  • Query DSL은 가독성도 좋고, 복잡한 쿼리 작성 뿐 아니라, 동적 쿼리 생성에도 유리하다.