Post

어쨌든 Hibernate는 구현체이다

어쨌든 Hibernate는 구현체이다

image.png

📌 개요

하나만 짚고 넘어가자. JPA 의 쿼리 언어는 JPQL 이다. JPA구현체 중 하나는 Hibernate 이며, Hibernate의 쿼리 언어는 HQL 이다. 사실 하나가 아니고 세 개다.

내가 ‘구현’이라고 하지 않았는가? JPA라는 인터페이스구현한 것이 Hibernate이다. 이는 곧 Hibernate가 독자적인 기능을 가질 수 있다는 것을 의미한다. JPQL에는 없으나 HQL에는 있는 기능과 문법에 대해 알아보자.

📌 LIMIT / OFFSET

표준 JPQL은 LIMIT, OFFSET 문법이 없다. 대신 동일한 동작을 수행하는 메서드가 존재한다.

1
2
3
Query q = em.createQuery("SELECT m FROM Member m ORDER BY m.id");
q.setFirstResult(0);
q.setMaxResults(10);

setFirstResult 는 쿼리 결과 중 몇 번째 엔티티부터 시작할지를 지정하며, OFFSET 과 동일한 동작을 수행한다.

setMaxResults 는 쿼리 결과 중 최대 몇 개의 결과만 가져올지를 지정하며, LIMIT 과 동일한 동작을 수행한다.

1
@Query("SELECT m FROM Member m ORDER BY m.id LIMIT 10 OFFSET 20")

반면 HQL은 LIMITOFFSET 을 쿼리 문자열에 사용할 수 있다.

1
2
3
Optional<ChatMessage> findFirstByChatRoomIdOrderByCreatedAtDesc(long chatRoomId);

List<ChatMessage> findTop3ByChatRoomIdOrderByCreatedAtDesc(long chatRoomId);

다만 LIMIT 은 JPA의 메서드를 통해 구현할 수 있다. findFirstXXXLIMIT 1 , findTopNXXXLIMIT N 과 동일한 동작을 수행한다.

OFFSET 은 그런 거 없다. Pageable 을 사용해야 한다.

📌 CONCAT

1
@Query("SELECT CONCAT(m.firstName, m.lastName) FROM Member m")

JPQL은 두 문자열을 붙이기 위해 CONCAT 메서드를 사용한다.

다만 이 방법은 두 문자열만 붙일 수 있다는 단점이 있으며, 여러 문자열을 붙이기 위해 CONCAT을 중첩하여 사용해야 한다.

1
2
3
@Query("SELECT m.firstName || ' ' || m.lastName FROM Member m")

@Query("SELECT concat(m.firstName, ' ', m.lastName, '!', m.email) FROM Member m")

HQL은 파이프 연산(||)을 지원하며, concat 메서드 또한 두 개 이상의 파라미터를 받을 수 있다.

📌 INSERT

JPQL은 기본적으로 INSERT 연산을 지원하지 않는다. JPQL은 일반적으로 SELECT, UPDATE, DELETE 연산만 지원한다.

1
@Query("INSERT INTO EntityA (field1, field2) SELECT b.fieldX, b.fieldY FROM EntityB b WHERE ..")

HQL는 INSERT INTO ... SELECT ... 문법을 지원한다. 대량의 데이터를 한 번에 삽입할 수 있다.

다만 일반적인 SQL처럼 INSERT INTO ... VALUES ... 는 불가능하다.

📌 결론

어쨌든 Hibernate는 구현체이다.

구현체의 의존성이 강해지면 다른 구현체로 변경 시 문제가 발생할 수 있다. JPA 명세를 따르도록 작성하는 것이 좋을 것 같다.

This post is licensed under CC BY 4.0 by the author.