- 개인 공부 목적으로 작성한 글입니다.
- 아래 출처를 참고하여 작성하였습니다.
목차
- Intro
- Gradle 설정
- QueryDSL Configuration(Java Config)
- 테스트용 Entity, Repository
- QueryDSL 사용방법1. 기본 사용법
- QueryDSL 사용방법2. Spring Data Jpa Custom Repository 적용
- QueryDSL 사용방법3. 상속/구현 없는 Repository
1. Intro
- Spring Data JPA 프로젝트에 QueryDSL을 적용하는 세 가지 방법에 대해 알아보겠습니다.
- 여기서는 gradle을 사용합니다.
2. Gradle 설정
- querydsl-jpa : QueryDSL JPA 라이브러리입니다.
- querydsl-apt : 쿼리 타입(Q)를 생성할 때 사용하는 라이브러리입니다.
- 쿼리 타입이란 엔티티를 기반으로 생성된 쿼리용 클래스를 말합니다.
//build.gradle
plugins {
id 'org.springframework.boot' version '2.5.5'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
def querydslVersion = '4.1.3'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation group: 'com.querydsl', name: 'querydsl-jpa', version: querydslVersion
implementation group: 'com.querydsl', name: 'querydsl-core', version: querydslVersion
implementation group: 'com.querydsl', name: 'querydsl-apt', version: querydslVersion
annotationProcessor "com.querydsl:querydsl-apt:${querydslVersion}:jpa"
annotationProcessor("jakarta.persistence:jakarta.persistence-api")
annotationProcessor("jakarta.annotation:jakarta.annotation-api")
}
3. QueryDSL Configuration(Java Config)
- 아래 설정으로 프로젝트 어느 곳에서나 JPAQueryFactory를 주입받아 QueryDSL을 사용할 수 있게 됩니다.
package com.example.querydsltest.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuerydslConfiguration {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
4. 테스트용 Entity, Repository
- 테스트로 사용할 Entity와 테스트 데이터를 넣고 검증할 Repository를 생성해놓겠습니다.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Academy {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String address;
@Builder
public Academy(String name, String address) {
this.name = name;
this.address = address;
}
}
@Repository
public interface AcademyRepository extends JpaRepository<Academy, Long> {
}
5. QueryDSL 사용방법1. 기본 사용법
- QuerydslRepositorySupport를 상속받아 사용하는 방법입니다.
- 또한, 위에서 Config로 등록했던 jpaQueryFactory Bean을 생성자 인잭션으로 주입받아 사용합니다.
- 이 코드에서 중요한 건 빌드를 하여 생성된 Entity의 QClass를 사용합니다.
- 해당 코드에서 option+enter를 사용해 Import를 진행하시면 됩니다.
- 그럼 아래와 같이 Import가 된 것을 확인할 수 있습니다.
//...
import static com.example.querydsltest.domain.QAcademy.academy;
//...
@Repository
public class AcademyRepositorySupport extends QuerydslRepositorySupport {
private final JPAQueryFactory queryFactory;
public AcademyRepositorySupport(JPAQueryFactory queryFactory) {
super(Academy.class);
this.queryFactory = queryFactory;
}
public List<Academy> findByName(String name) {
return queryFactory.selectFrom(academy)
.where(academy.name.eq(name))
.fetch();
}
}
Test Code
- Querydsl이 정상작동했다면 findByName이라는 메소드가 정상작동할 것입니다.
- 아래와 같이 테스트 코드를 작성해서 검증해보겠습니다.
- 코드는 간단합니다.
- 1개의 Academy 데이터를 넣고, Querydsl로 만든 findByName메소드로 조회시 정상적으로 결과가 나오는지 확인합니다.
@ExtendWith(SpringExtension.class)
@SpringBootTest
class AcademyTest {
@Autowired
private AcademyRepository academyRepository;
@Autowired
private AcademyRepositorySupport academyRepositorySupport;
@Test
public void querydsl_기본_기능_확인() {
//given
String name = "jojoldu";
String address = "jojoldu@gmail.com";
academyRepository.save(new Academy(name, address));
//when
List<Academy> result = academyRepositorySupport.findByName(name);
//then
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getAddress()).isEqualTo(address);
}
}
6. QueryDSL 사용방법2. Spring Data Jpa Custom Repository 적용
- 위와 같은 방식으로도 QueryDSL을 사용할 수 있지만, 한 가지 단점이 있습니다.
- 항상 2개의 Repository를 의존성으로 받아야 한다는 점입니다.
- 아래 두 개의 Repository가 기능을 나눠가져서 그렇습니다.
- QueryDSL의 Custom Repository, JpaRepository의 Repository
- 이를 해결하기 위해 Spring Data JPA에서는 Custom Repository를 JpaRepository 상속 클래스에서 사용할 수 있도록 기능을 지원합니다.
- 전체적인 그림은 아래와 같습니다.
- 위와 같이 구성하면 AcademyRepository에서 AcademyRepositoryImpl의 코드도 사용할 수 있습니다.
- Custom이 붙은 인터페이스를 상속한 Impl 클래스의 코드는 Custom 인터페이스를 상속한 JpaRepository에서도 사용할 수 있습니다.
- 일종의 공식이라고 보면 됩니다.
- Custom과 Impl만 기억하면 됩니다.
- 코드로 진행해보겠습니다.
- 먼저 AcademyRepository와 같은 위치에 AcademyRepositoryCustom 인터페이스와 AcademyRepositoryImpl 클래스를 생성합니다.
public interface AcademyRepositoryCustom {
List<Academy> findByName(String name);
}
- Impl 클래스는 기존에 있던 Support 클래스 코드를 참고해서 구현하면 됩니다.
- Impl 클래스는 페이징이 필요한 게 아니라면 QuerydslSupport 상속 코드를 추가할 필요는 없습니다.
- 결국 JPAQueryFactory를 통해서 작동하기 때문입니다.
import static com.example.querydsltest.domain.QAcademy.academy;
@RequiredArgsConstructor
public class AcademyRepositoryImpl implements AcademyRepositoryCustom {
private final JPAQueryFactory queryFactory;
@Override
public List<Academy> findByName(String name) {
return queryFactory.selectFrom(academy)
.where(academy.name.eq(name))
.fetch();
}
}
- 그리고 이 코드를 AcademyRepository에서 쓸 수 있게 상속 구조로 변경합니다.
- 이제 AcademyRepository가 정상 동작하는지 테스트 해보면 됩니다.
@Repository
public interface AcademyRepository extends JpaRepository<Academy, Long>, AcademyRepositoryCustom {
}
Test Code
@ExtendWith(SpringExtension.class)
@SpringBootTest
class AcademyTest {
@Autowired
private AcademyRepository academyRepository;
@Test
public void querydsl_기본_기능_확인() {
//given
String name = "jojoldu";
String address = "jojoldu@gmail.com";
academyRepository.save(new Academy(name, address));
//when
List<Academy> result = academyRepository.findByName(name);
//then
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getAddress()).isEqualTo(address);
}
}
7. QueryDSL 사용방법3. 상속/구현 없는 Repository
- 마지막 방식은 QueryDSL만으로 Repository를 구성하는 방법입니다.
- 아래처럼 JPAQueryFactory만 있으면 QueryDSL을 사용할 수 있습니다.
- 최소한의 Bean 등록을 위해 @Repository를 선언합니다.
- 별도의 extends / implements 없이 JPAQueryFactory만 있으면 됩니다.
- 특정 Entity만 사용해야한다는 제약도 없습니다.
import static com.example.querydsltest.domain.QAcademy.academy;
@RequiredArgsConstructor
@Repository
public class AcademyQueryRepository {
private final JPAQueryFactory queryFactory;
public List<Academy> findByName(String name) {
return queryFactory.selectFrom(academy)
.where(academy.name.eq(name))
.fetch();
}
}
Test Code
@ExtendWith(SpringExtension.class)
@SpringBootTest
class AcademyTest {
@Autowired
private AcademyRepository academyRepository;
@Autowired
private AcademyQueryRepository academyQueryRepository;
@Test
public void querydsl_기본_기능_확인() {
//given
String name = "jojoldu";
String address = "jojoldu@gmail.com";
academyRepository.save(new Academy(name, address));
//when
List<Academy> result = academyQueryRepository.findByName(name);
//then
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getAddress()).isEqualTo(address);
}
}
출처
'JPA > QueryDSL' 카테고리의 다른 글
about QueryDSL (0) | 2021.10.13 |
---|