JPQL vs query DSL

조성권·2022년 3월 19일
3
post-thumbnail

오늘은 JPQLquery DSL의 차이에 대해 알아보도록 하겠다.

1. JPQL

JPQLJPA의 일부로 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 상승)


query DSL

앞서 언급한 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. 동적 쿼리 구현 가능

profile
천천히, 완벽히 배워나가고자 하는 웹 서비스 엔지니어

0개의 댓글