JPQL과 native query
업데이트:
JPQL 개요
JPA를 사용하다보니 JPA만으로 간단하게 해결되지 않는 조회가 필요했다.
JPQL은 SQL을 추상화해 SQL처럼 보이는
Query Language이다.
JPQL 사용하기
Repository 클래스에서 @Query
어노테이션으로 사용한다.
1
2
3
// BoardRepository.java ...
@Query(value="SELECT b FROM Board b")
List<Board> findAllBy();
문제 상황 1
JPQL 사용 중 FROM절 서브쿼리를 사용하려고 했는데, JPQL은 FROM 서브쿼리를 지원하지 않는다고 한다.
추천하지는 않지만, nativeQuery
옵션으로 추상화되지 않은 SQL을 직접 사용할 수 있다.
해결: Native Query 사용해보기
1
2
3
4
5
6
7
8
9
10
// BoardRepository.java ...
@Query(value="SELECT board_id, created_at, nickname, title, views, writer "
+ "FROM ( "
+ " SELECT * "
+ " FROM board "
+ " WHERE TIMESTAMPDIFF(HOUR, created_at, NOW()) < 25 "
+ ") board "
+ "ORDER BY views DESC "
+ "LIMIT 5;", nativeQuery=true)
List<BoardListMapping> findDailyTop();
이걸로 해결인가 싶었다.
문제 상황 2
findDailyTop()으로 데이터를 조회했더니, board_id, create_at 컬럼의 데이터가 null으로 조회되었다.
찾아보니 JPQL은 nativeQuery의 snake_case를 camelCase로 변환해주지 않았다.
따라서 boardId, createdAt 등으로 정의된 엔티티 컬럼이 조회되지 않은 것이었다.
그렇다면..
해결: alias 사용하기
1
2
3
4
5
6
7
8
9
@Query(value="SELECT board_id AS 'boardId', created_at AS 'createdAt', nickname, title, views, writer "
+ "FROM ( "
+ " SELECT * "
+ " FROM board "
+ " WHERE TIMESTAMPDIFF(HOUR, created_at, NOW()) < 25 "
+ ") board "
+ "ORDER BY views DESC "
+ "LIMIT 5;", nativeQuery=true)
List<BoardListMapping> findDailyTop();
조회 쿼리에 Alias를 주어, board_id를 boardId로 변환해 해결했다.
사족
JPA, JPQL은 추상화되어 어떤 Database에도 이식 가능함이 장점인데, nativeQuery가 포함되는 순간 유연성이 떨어진다.
Native Query를 사용하지 않는 다른 방법을 생각해보자.
댓글남기기