JPQL에서 QueryDSL로 전환하기
들어가기에 앞서
현재 프로젝트의 쿼리는 모두 JPQL로 작성하였다. 이 프로젝트가 JPA를 공부하고 처음해보는 프로젝트이라서 기본적으로 사용하는 표준 방법들을 사용해본 후에 더 수월하게 하는 방법들을 적용해가는 것이 내가 공부한 것을 더 확실하게 이해할 수 있다고 생각했다.
JPA를 사용하면 QueryDSL을 사용하는 것이 필수라고는 이야기하지만 내가 그것을 직접 느껴봐야한다고 생각했고 솔직히 프로젝트를 시작하기 전에는 얼마나 크게 차이가 날려나 라는 생각도 했었는데 JPQL을 실제로 사용해보고 QueryDSL을 공부해보니 '진짜 엄청난 차이가 있구나' 라는 것을 느끼면서 전환을 결심했다.
혹시라고 QueryDSL에 대해서 잘 모르신다면 [JPA] - QueryDSL 사용이유와 사용방법을 참고하면 될 것이다.
QueryDSL로 전환하는 이유
QueryDSL로 바꾸게 된 이유에는 크게 2가지의 이유가 있다.
- JPQL과 비교해서 압도적으로 우세한 특징들을 가지고 있다.
- JPA를 사용하는 사람들에게는 필수적인 라이브러리가 되어버렸다.
(1) JPQL과 비교해서 압도적으로 우세한 특징들을 가지고 있다.
JPQL은 쿼리를 작성할 때 문자열로 작성한다는 특징이 있다. 사실 JPQL뿐만 아니라 JDBCTemplate, MyBatis등 모든 것들이 쿼리를 작성할 때 문자열에 작성하는 방식으로 진행되었다.
이 방식이 너무나도 익숙하기는 하지만 문제점이 분명히 있었다.
문자열로 쿼리를 작성하면 오타를 찾기가 쉽지 않다. 개발자도 사람이고 직접 타이핑을 해야하기 떄문에 수 많은 쿼리들을 만들다보면 오타가 발생할 수 밖에 없다. 이런 오타나 잘못된 입력들을 컴파일에러로 발견할 수 없고 반드시 실행을 시켜야만 잘못된 것을 발견할 수 있다. 더 심각한 경우는 해당 쿼리가 동작하기 전까지 알 수 없는 경우이다...
QueryDSL은 모든 쿼리를 자바코드로 작성하기 때문에 오타나 잘못된 입력이 있다면 컴파일 에러로 모두 잡아준다. 그렇기 때문에 사전에 문제를 예방할 수 있다.
그리고 문자열로 작성한 쿼리에서 동적쿼리를 사용하기 위해서는 많은 조건문들로 복잡해지는 코드를 만들어야 하는데 QueryDSL은 이런 문제도 깔끔하게 해결하고 있다.
(2) JPA를 사용하는 사람들에게는 필수적인 라이브러리가 되어버렸다.
위의 이유처럼 QueryDSL은 너무나도 강력한 기능을 자랑하기 때문에 JPA를 사용하는 곳이라면 기업이든 개인이든 필수적으로 QueryDSL을 사용하고 있다. 모두가 사용하는 기술이라는 것은 그만큼의 장점을 가지고 있다는 것이고 그만큼 대중적인 기술이라는 것이다. 혼자서 뒤쳐지지 않기 위해서라도 중요한 기술은 꼭 학습해볼 필요가 있다고 생각했다. 그리고 새로운 기술은 언제나 신나는 법이다.
QueryDSL전환 과정
전환하는 모든 코드를 보여주기는 힘들지만 일부 전환하는 과정을 보여주고자 한다. QueryDSL의 설정은 이미 마친후에 진행하는 것이다.
필자는 SpringDataJpa를 사용하기 때문에 이에 맞게 만들어주어야 한다.
- MemberRepositry(Interface)
- MemberRepositoryCustom(Interface)
- MemberRrepositryImpl
이렇게 총 3개의 파일을 이용해서 만들어보자.
먼저 MemberRepositoryCustom을 만들어보자.
public interface MemberRepositoryCustom {
List<Member> findByMemberIdAndMoreType(Long member_id, String value);
}
메소드를 하나 선언했다.
이제 구현체인 MemberRrepositryImpl로 쿼리를 생성할 것이다.
import static com.ssung.travelDiary.domain.members.QMember.*;
public class MemberRepositoryImpl implements MemberRepositoryCustom {
private final JPAQueryFactory queryFactory;
public MemberRepositoryImpl(EntityManager em) {
this.queryFactory = new JPAQueryFactory(em);
}
@Override
public List<Member> findByMemberIdAndMoreType(Long member_id, String value) {
return queryFactory
.selectFrom(member)
.where(member.id.eq(member_id).not()
.and(member.username.contains(value))
)
.fetch();
}
}
QMember는 static import시켜서 사용했다.
마지막으로 MemberRepositry를 만들어서 위에 만든 쿼리를 상속받도록 하자.
public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {
}
이제 필요한 곳에서 MemberRepository를 통해서 QueryDSL로 만든 쿼리를 사용할 수 있게 되었다.
이러한 방식으로 다른 JPQL도 모두 QueryDSL로 전환하였다.