요새 코드를 좀 둘러보다가 보면 한번 씩 이런 형태의 코드를 본 적이 있었다.
JPAQeuryFactory.selectFrom(post)
.where(post.id.eq(user.id))
.orderBy(post.created_at);
JPA도 편하지만, 조금 구체적으로 조회를 할 때 더욱 효율적일것 같다는 생각에 자료를 조금 찾아보기 시작했다.
스프링에서 SQL문법과 비슷하게 작성을 하기 위해서 어떻게 해야 하는지에 대해 검색을 좀 해보았는데, Native Query를 작성하는 Query 어노테이션이 자주 나오게 되었는데 이는 JPA에서 권장하는 내용은 아니라고 들어 이와 관련된 내용들은 깊게 찾아보지 않았다.
그렇게 찾게된 방법이 바로 QueryDSL 이었다.
QueryDSL을 사용함에 있어 이것이 무엇인지, 왜 사용하는지에 대해 찾아보게 되었다.
이렇게 총 3가지의 장점을 언급해 주었다.
build.gradle에서 간단한 설정만 해주면 된다.
plugins{
id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'
id 'java'
}
...
implementation 'com.querydsl:querydsl-jpa'
implementation 'com.querydsl:querydsl-apt'
plugin에 위 코드를 추가하고, 아래 두 개의 패키지를 implementation 해준다.
그리고 맨 아래쪽에 아래 코드를 추가해주자.
tasks.named('test') {
useJUnitPlatform()
}
//querydsl 추가
//def querydslDir = 'src/main/generated'
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
library = "com.querydsl:querydsl-apt"
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main {
java {
srcDirs = ['src/main/java', querydslDir]
}
}
}
compileQuerydsl{
options.annotationProcessorPath = configurations.querydsl
}
configurations {
querydsl.extendsFrom compileClasspath
}
이 코드를 작성하고 gradle을 적용해주고 compileQuerydsl
을 실행시켜준다.
Inteliij를 사용하고 있다면, compileQuerydsl
좌측 코드라인에 보면 초록색 실행버튼이 있을것이다. 해당 버튼을 눌려주면 compileQuerydsl
이 실행 되며 build
폴더 안에 generated
폴더가 생기고, 여태 만든 entity들이 Q라는 키워드가 붙은 상태로 추가가 되어 있을것이다.
이 외에도 IDE 우측을 보면 Gradle 탭을 클릭 후 [Project] → Tasks → other 경로로 들어오면 아래와 같이 compileQuerydsl
이 있을텐데 이를 더블클릭 해주면 된다.
기존 Repository가 저장된 폴더에 새로운 클래스 파일을 만들고 아래와 같이 작성을 한다.
@Repository
public class PostCustomRepositoryImpl implements PostCustomRepository {
private final long NEW_POST_LIMIT_COUNT = 5L;
private final JPAQueryFactory jpaQueryFactory;
public PostCustomRepositoryImpl(JPAQueryFactory jpaQueryFactory) {
this.jpaQueryFactory = jpaQueryFactory;
}
@Override
public List<PostEntity> findFiveNewPosts() {
return jpaQueryFactory
.select(postEntity)
.from(postEntity)
.limit(NEW_POST_LIMIT_COUNT);
}
}
여기서 보면 PostCustomRepository
라는것을 상속받고 있는데 이는 새로운 인터페이스 이다.
public interface PostCustomRepository {
List<PostEntity> findFiveNewPosts();
}
그리고 이렇게 새로 만들어진 interface는 기존 Repository에 상속시켜준다.
public interface PostRepository extends JpaRepository<PostEntity, String>, PostCustomRepository{
}
다중 상속이 되기 때문에 이렇게 할 수 있는것이다.
이렇게 하면 Service단에서 PostRepository
만을 불러와도 다형성 때문에 findFiveNewPosts()
메서드를 사용할 수 있게 된다.
즉,
@Service
public class PostService {
@Autowired
private PostRepository postRepository;
public List<PostEntity> getNewFivePost() {
return postRepository.findFiveNewPosts();
}
}
그런데 이상하다 중간에 JPAQueryFactory라는것이 있다. 이것은 무엇일까
이는, JPQL 쿼리를 위한 JPAQuery의 Factory 패턴을 적용한 것이다.
결국, JPAQuery를 사용한다는 사실은 변함이 없다.
그저 JPAQuery 를 Factory 패턴을 적용했다는 것인데, 이는 다른 글에서 이야기를 해보자.