데이터베이스에서 값을 가져올 때는 앞 절에서 소개한 것처럼 메서드의 이름만으로 쿼리 메서드를 생성할 수도 있고 이번 절에서 살펴볼 @Query
어노테이션을 사용해 직접 JPQL
을 작성할 수도 있다.
JPQL
을 사용하면 JPA
구현체에서 자동으로 쿼리 문장을 해석하고 실행하게 된다. 만약 데이터베이스를 다른 데이터베이스로 변경할 일이 없다면 직접 해당 데이터베이스에 특화된 SQL
을 작성할 수 있다.
먼저 기본적인 JPQL
을 사용해 상품정보를 조회하는 메서드를 리포지토리에 추가한다.
@Query("SELECT p FROM Product AS p WHERE p.name = ?1")
List<Product> findByName(String name);
@Query
어노테이션을 사용해 JPQL 형식의 쿼리문 작성FROM
뒤에서 엔티티 타입을 지정하고 별칭 생성 (AS는 생략 가능)WHERE
절에서는 SQL과 마찬가지로 조건을 지정위 예제의 조건문에서 사용한 ?1
은 파라미터를 전달받기 위한 인자에 해당한다. 하지만 이 같은 방식을 사용할 경우 파라미터의 순서가 바뀌면 오류가 발생할 가능성이 있어 @Param
어노테이션을 사용하는 것이 좋다.
@Query("SELECT p FROM Product p WHERE p.name = :name")
List<Product> findByNameParam(@Param("name") String name);
이처럼 파라미터를 바인딩하는 방식으로 메서드를 구현하면 코드의 가독성이 높아지고, 파라미터의 순서가 바뀌어도 오류가 발생하지 않아 유지보수가 수월해진다.
Hiberate
에서 생성되는 쿼리앞에서 살펴본 두 예제는 Hibernate
에서 다음과 같이 동일한 쿼리를 생성해서 실행한다.
Hibernate:
select
product0_.number as number1_0_,
product0_.created_at as created_2_0_,
product0_.name as name3_0_,
product0_.price as price4_0_,
product0_.stock as stock5_0_,
product0_.updated_at as updated_6_0_
from
product product0_
where
product0_.name=?
@Query
를 사용하면 엔티티 타입이 아니라 원하는 칼럼의 값만 추출할 수 있다.
@Query("SELECT p.name, p.price, p.stock FROM Product p WHERE p.name = :name")
List<Object[]> findByNameParam2(@Param("name") String name);
이처럼 SELECT
에 가져오고자 하는 칼럼을 지정하면 된다. 이때 메서드에서는 Object
배열의 리스트 형태로 리턴 타입을 지정해야 한다.
Hiberate
에서 생성되는 쿼리위 메서드를 호출했을 때 생성되는 쿼리는 다음과 같다.
Hibernate:
select
product0_.name as col_0_0_,
product0_.price as col_1_0_,
product0_.stock as col_2_0_
from
product product0_
where
product0_.name=?