JPQL을 작성하다보면 DB의 내장함수가 필요한 순간이 있다.
그런데, JPQL은 모든 데이터베이스의 내장함수를 다 지원하지 않는다.
개인 프로젝트를 진행하면서 알게 된 방법은 3가지 정도 있는데 각각에 대해서 알아보자.
H2 DB를 기준으로, 한 주간 작성된 게시글을 조회하는 쿼리를 작성한다고 가정하자.
hibernate의 방언(Dialect) 클래스에 등록되어 있는 각 DB별 내장함수들을 사용할 수가 있다.
먼저, function 문법을 사용한 JPQL을 살펴보자.
List<Post> findFunction = em.createQuery("select p from Post p where function('datediff', day, p.createdDate, current_timestamp) between 0 and 6", Post.class)
.getResultList();
function()
은 hibernate가 지원하고 있는 각 DB별 내장함수를 쓰는데에 사용되는 함수이다.
첫 번째 인자는 사용할 내장함수의 이름을 적어주고, 그 뒤의 인자들은 해당 내장함수가 필요로 하는 인자를 입력해주면 된다.
H2Dialect.class의 237번 행을 확인해보면 datediff
함수가 등록되어 있는 것을 확인할 수 있다.
모든 내장함수를 다 지원하지는 않기 때문에 방언 클래스를 잘 확인해보고 사용하자.
JPA는 실제 데이터베이스 쿼리를 사용하는 것도 지원한다.
List findByNative = em.createNativeQuery("select * from post where datediff(day, created_date, current_timestamp) between 0 and 6", Post.class)
.getResultList();
createNativeQuery
메서드를 통해서 실제 데이터베이스 쿼리를 작성하여 데이터를 조회할 수가 있다.
내장함수가 필요한 부분을 쿼리가 아니라 서버에서 별도의 로직을 통해서 처리하는 방법이다.
List<Post> findAll = em.createQuery("select p from Post p", Post.class)
.getResultStream()
.filter(p -> p.getCreatedDate().isAfter(LocalDateTime.now().minusWeeks(1L)))
.collect(Collectors.toList());
createQuery
메서드의 반환 타입인 Query
클래스가 Stream을 반환하는 메서드를 지원하므로 스트림을 통해서 원하는 데이터만 뽑아내서 사용할 수 있다.
꼭 스트림을 사용하지 않더라도 모든 데이터를 조회해서 해당 데이터를 적절하게 조작하여 원하는 데이터만 취하면 된다.
개인 프로젝트를 진행하면서 처음에는 1번 방식으로 구현했었는데 불편한 점이 있었다.
나의 경우, 로컬에서는 H2 DB에 맞는 내장함수를 사용해서 개발하다가 배포할 때는 MySQL에 맞는 내장함수로 수정해야했기 때문에 너무 번거롭고 비효율적이고 유연성이 떨어졌다.
어떤 방식이 더 성능이 좋게 나오는지 테스트는 해보지 못했지만 나의 경험상 서버단에서 해결하는 것이 가장 낫다고 생각이 된다.