Querydsl 적용하기
Integrate Spring Data JPA with Querydsl
Querydsl Framework는 초기 설정이 다소 복잡하지만, ORM 기술을 보다 효과적으로 활용할 수 있게 해줍니다. 그래서 새로운 프로젝트를 시작할 때 항상 Spring Data JPA와 함께 구성합니다.
이번 포스팅에서는 프로젝트에 Querydsl을 적용하고 Spring Data JPA와 통합하는 방법을 살펴보겠습니다.
Prerequisites
Spring Initializr를 통해 Spring Boot 프로젝트를 생성합니다:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
- Java 17
- Gradle
- MySQL 8
- Dependencies
- Spring Boot 3.1.4
- Spring Data JPA
- MySQL Driver
- Lombok
Querydsl이 정상적으로 동작하는지 확인하기 위해 데이터베이스 테이블을 추가합니다.
create table ACCOUNTS
(
id bigint auto_increment primary key,
username varchar(255) not null,
password varchar(255) not null
);
application.yml
파일에 DataSource
정보를 추가하여 데이터베이스와 연결합니다.
spring:
datasource:
jdbc-url: jdbc:mysql://localhost:3306/querydsl
username: catsriding
password: catsriding
그리고 생성한 ACCOUNTS
테이블을 JPA Entity로 매핑합니다.
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "ACCOUNTS")
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "username", nullable = false)
private String username;
@Column(name = "password", nullable = false)
private String password;
}
애플리케이션을 실행하여 정상적으로 동작하는지 확인한 후 다음 단계를 진행합니다.
Configuring Querydsl
Querydsl을 사용하면 복잡한 SQL 쿼리를 간단하고 안전하게 작성할 수 있습니다. 이를 위해서는 먼저 Querydsl의 의존성을 프로젝트에 추가해야 합니다. 의존성을 추가하면 Querydsl이 제공하는 다양한 기능을 사용할 수 있게 되며, JPA와의 통합도 가능해집니다.
아래와 같이 build.gradle
파일을 열고 필요한 Querydsl 의존성을 추가합니다:
dependencies {
+ implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' // 1️⃣
+ annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" // 2️⃣
+ annotationProcessor "jakarta.annotation:jakarta.annotation-api" // 3️⃣
+ annotationProcessor "jakarta.persistence:jakarta.persistence-api" // 4️⃣
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
- 1️⃣ Querydsl의 JPA 모듈을 프로젝트에 추가합니다. 이는 Querydsl의 핵심 도구로, 타입-세이프한 쿼리를 작성하는 데 사용되며, JPA와 호환됩니다.
- 2️⃣ Querydsl의 APT(Annotation Processing Tool) 모듈을 추가합니다. 이 도구는 Querydsl 실행에 필요한 메타모델을 생성합니다.
- 3️⃣ Jakarta Annotation API를 추가합니다. 이는 Jakarta EE 플랫폼에서 사용되는 공통 어노테이션을 정의하며, Querydsl이 어노테이션을 처리할 때 필요합니다.
- 4️⃣ Jakarta Persistence API를 추가합니다. 이 API는 JPA(Java Persistence API)를 표준화하였으며, Querydsl이 JPA와 함께 작동하는 데 필요합니다.
Querydsl은 JPA의 EntityManager
를 사용하여 Java 코드를 SQL 쿼리로 변환하는 역할을 합니다. 이를 위해 EntityManager
를 주입받아 사용하는 JPAQueryFactory
클래스를 활용합니다. 이 JPAQueryFactory
를 리포지토리 구현체에서 직접 인스턴스화하는 대신 Spring Bean으로 등록하면, 리포지토리에서 편리하게 주입받아 사용할 수 있습니다:
@Configuration
public class QuerydslConfig {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
@PersistenceContext
: JPA의EntityManager
를 주입받기 위한 어노테이션입니다.JPAQueryFactory
: Querydsl을 사용하여 타입-세이프한 쿼리를 작성하기 위한 클래스입니다.
다음은 Querydsl에서 SQL을 작성할때 필요한 Q-Type 클래스를 생성하기 위해서, IntelliJ IDEA나 Gradle 명령어를 통해 프로젝트를 빌드합니다:
$ gradle build
프로젝트 빌드가 성공하면 build
디렉토리 하위에 Querydsl의 Q-Type 파일이 생성됩니다. Q는 Query의 줄임말이며 QAccount
와 같이 Entity 클래스명 앞에 접두사로 붙습니다.
$ exa -alhFT
drwxr-xr-x@ - catsriding 9 Dec 01:26 ./
drwxr-xr-x@ - catsriding 9 Dec 01:26 ├── build/
drwxr-xr-x@ - catsriding 9 Dec 01:26 │ ├── generated/
drwxr-xr-x@ - catsriding 9 Dec 01:26 │ │ └── sources/
drwxr-xr-x@ - catsriding 9 Dec 01:26 │ │ ├── annotationProcessor/
drwxr-xr-x - catsriding 9 Dec 01:31 │ │ │ └── java/
drwxr-xr-x - catsriding 9 Dec 01:31 │ │ │ └── main/
drwxr-xr-x - catsriding 9 Dec 01:31 │ │ │ └── app/
drwxr-xr-x - catsriding 9 Dec 01:31 │ │ │ └── catsriding/
drwxr-xr-x - catsriding 9 Dec 01:31 │ │ │ └── querydsl/
drwxr-xr-x - catsriding 9 Dec 01:31 │ │ │ └── entity/
.rw-r--r-- 967 catsriding 9 Dec 01:31 │ │ │ └── QAccount.java
IntelliJ IDEA는 build
디렉토리를 기본적으로 프로젝트 소스에서 제외합니다. IntelliJ에서 Q-Type을 import 할 수 없다면 Q-Type이 위치한 디렉토리가 제외(Excluded) 되었는지 확인하고, 해당 디렉토리를 Generated Sources Root로 변경합니다.
Integrating JpaRepository
Spring Data JPA를 사용할 때 일반적으로 아래와 같이 JpaRepository<T, ID>
인터페이스를 확장한 리포지토리를 구성하게 됩니다.
public interface AccountRepository extends JpaRepository<Account, Long> {
}
Querydsl을 통합하여 사용하기 위해서는 JpaRepository
인터페이스를 확장한 Querydsl 전용 인터페이스를 추가하고, 이를 구현하는 클래스를 만들어야 합니다. 이렇게 하는 이유는 Spring Data JPA에서 제공하는 CRUD 기능과 Querydsl의 기능을 모두 활용할 수 있게 하기 위해서입니다.
먼저, Querydsl 전용 인터페이스를 추가합니다. 인터페이스 이름은 보통 Support
, Helper
, Extension
등의 접미사를 사용합니다. 저는 개인적으로 Extension
접미사를 주로 사용하는 편입니다:
public interface AccountRepositoryExtension {
}
그 다음, 실제 SQL 쿼리를 작성하게 될 인터페이스 구현 객체를 생성합니다. 이 구현 객체의 이름은 반드시 마지막에 Impl
접미사를 붙여야 합니다. 이는 Spring Data JPA가 해당 클래스를 자동으로 인식하게 합니다. 그리고 위에서 Spring Bean으로 등록한 JPAQueryFactory
를 주입받습니다.
@RequiredArgsConstructor
public class AccountRepositoryImpl implements AccountRepositoryExtension {
private final JPAQueryFactory queryFactory;
}
마지막으로, AccountRepository
로 돌아가서 Querydsl 리포지토리 인터페이스를 상속 목록에 추가합니다:
public interface AccountRepository extends JpaRepository<Account, Long>, AccountRepositoryExtension {
}
이렇게 하면 Querydsl을 프로젝트에 적용하고 Spring Data JPA와 통합하는 작업이 완료됩니다. Querydsl을 활용하여 간단한 조회 쿼리를 작성해보도록 하겠습니다.
먼저 Querydsl 전용 인터페이스에 메서드를 정의합니다:
public interface AccountRepositoryExtension {
+ List<Account> fetchAll();
}
그리고 구현 객체에서 이 메서드를 오버라이드하여 SQL 쿼리를 Java 코드로 작성합니다:
import static app.catsriding.querydsl.entity.account.QAccount.account;
@RequiredArgsConstructor
public class AccountRepositoryImpl implements AccountRepositoryExtension {
private final JPAQueryFactory queryFactory;
+ @Override
+ public List<Account> fetchAll() {
+ return queryFactory
+ .select(account)
+ .from(account)
+ .orderBy(account.id.desc())
+ .fetch();
+ }
}
이와 같이 Querydsl을 활용하면 Java 언어를 사용하기 때문에 IntelliJ IDEA의 자동완성 기능을 적극적으로 지원받을 수 있으며, 타입 세이프하게 SQL 쿼리를 작성할 수 있어 마치 애플리케이션 로직을 작성하는 듯한 진정한 ORM 경험을 제공합니다. Querydsl의 가장 강력한 기능 중 하나는 동적 쿼리 작성 능력인데, 이는 Querydsl 동적 쿼리 작성하기에서 자세히 다루어보겠습니다. 🐬
- Spring
- JPA
- Querydsl