오늘은 JPQL과 query DSL의 차이에 대해 알아보도록 하겠다.
JPQL은 JPA의 일부로 Query를 Table
이 아닌 객체(=엔티티)
기준으로 작성하는 객체지향 쿼리 언어라고 정의할 수 있겠다.
JPQL은 객체
를 기준으로 모든 것이 움직이기 때문에 개발할 때, Table에 매핑되는 객체
가 반드시 존재해야 하며 당연하게도 검색할 때도 Table
이 아닌 객체
를 대상으로 검색해야 한다.
전반적인 특징에 대해 간단히 다시 정리한다면 다음과 같다.
JPQL 특징
1. SQL을 추상화한 JPA의객체지향 쿼리
2. Table이 아닌Entity 객체
를 대상으로 개발
3. Entity와 속성은대소문자 구분
(PERSON <> person)
4.별칭(alias)
사용 필수
JPQL을 실제 구현하는 방식으로는 크게 두 가지 방식이 있다.
아래 예시를 통해 두 가지 방식에 대해 알아보도록 하자.
1. EntityManager 활용
@Autowired
EntityManager em;
Person person = new Person();
Person.setFirstName("Sungkwon");
Person.setLastName("Cho");
userRepository.save(person); // JPA 문법 (save == INSERT문)
TypedQuery<User> tq = em.createQuery("select p from Person p where p.FirstName = :firstName and p.LastName = :lastName", Person.class);
tq.setParameter("firstName", "Sungkwon");
tq.setParameter("lastName", "Cho");
List<Person> personList = tq.getResultList();
LOGGER.info("firstName: " + personList.get(0).getFirstName());
2. repository interface 활용
public interface PersonRepository extends JpaRepository<Person, Long>{
/* 변수 바인딩 시, ?시퀀스 사용하는 경우 */
@Query("select p from Person p where p.firstName = ?1 and p.lastName = ?2")
Person findPerson(String firstName, String lastName);
/* 변수 바인딩 시, :이름 사용하는 경우 */
@Query("select p from Person p where p.firstName = :firstName and p.lastName = :lastName")
Person findPerson2(@Param("firstName") String firstName, @Param("lastName") String lastName);
}
아마 보자마자 구현하는 방식에 있어 차이점이 확연히 드러날 것이다.
하지만, 결과적으로 이 둘의 공통점이자 문제점은 여전히 쿼리를 String 형태로 작성하고 있다는 점
이다.
문제점에 대해 다시 한번 정리하자면 아래와 같다.
JPQL의 문제점
1. JPQL은문자열(=String) 형태
이기 때문에개발자 의존적
형태
2.Compile 단계
에서 Type-Check가 불가능
3.RunTime 단계
에서 오류 발견 가능 (장애 risk 상승)
앞서 언급한 JPQL에 대한 보완을 위해 나온 것이 query DSL이라고 볼 수 있다.
query DSL
정적 타입을 이용해서 SQL, JPQL을 코드로 작성할 수 있도록 도와주는 오픈소스 빌더 API
query DSL을 사용하는 목적은 뚜렷하다.
기존 방식(Mybatis, JPQL, etc..)은 모두 문자열(=String) 형태
로 쿼리가 작성되었고 이로 인해 Compile 단계에서 Type-Check 불가
했다.
이러한 risk를 줄이기 위해 query DSL이 등장했고 이를 통해 Compile 단계에서 Type-check가 가능
해진 것이다.
이제 예시를 통해 query DSL을 사용하는 방법에 대해 확인해보도록 하자.
@PersistenceContext
EntityManager em;
public List<Person> selectPersonByNm(String firstNm, String lastNm){
JPAQueryFactory jqf = new JPAQueryFactory(em);
QPerson person = QPerson.person;
List<Person> personList = jpf
.selectFrom(person)
.where(person.firstName.eq(firstNm)
.and(person.lastName.eq(lastNm))
.fetch();
return personList;
}
앞서 작성했던 JPQL과 차이가 느껴지는가?
query DSL은 모든 쿼리에 대한 내용이 함수 형태
로 제공된다.
이렇게 엔티티(객체) + 함수
형태로 구성된 query DSL을 통해 구현된 코드는 오류가 존재할 시, Compile 단계에서 바로 확인 가능
하며 이에 따른 후속 조치가 가능하기 때문에 그만큼 risk가 줄어들게
되는 것이다.
물론, 단점도 존재한다. 바로 코드 라인수가 길어진다
는 것이다.
하지만 개인적인 생각으로는... 코드의 수가 조금 길어지더라도 가독성이 저하될만큼 코드가 복잡하거나 하지 않기 때문에 큰 단점이라 생각되진 않는다.
다시 한번, 특징을 정리한다면 아래와 같다.
query DSL 특징
1.문자
가 아닌코드
로 작성
2.Compile 단계
에서문법 오류
를 확인 가능
3. 코드자동 완성 기능
활용 가능
4.동적 쿼리
구현 가능