[Java] JPA specification vs @Query vs 메서드 명명 규칙

최지나·2024년 1월 29일

Spring Data JPA를 사용할 때, 데이터 베이스 쿼리를 생성하기 위한 방법은 크게 3가지가 존재한다

  • JPA Specification의 사용
  • @Query 어노테이션의 사용
  • Spring data의 명명 규칙 사용 (ex findById(id))
    각각의 접근 방식을 이해하고 언제 어떤 방법을 사용해야할지를 기록하고자 한다 😃

1. JPA Specification의 사용

사용 상황

  • 동적, 복잡한 쿼리를 사용할 때 유용. 쿼리의 기준이 사용자 입력이나 다른 비지니스 로직에 따라 변할 때 유용

예시

  • 게시판 댓글 조회시 - postId, -parentCommentId, 작성 날짜 범위 등과 같은 동적 필터에 기반하여 댓글을 조회해야하는 상황
public interface PostCommentRepository extends JpaRepository<PostComment, Long>, JpaSpecificationExecutor<PostComment> {
    // 다른 리포지토리 메서드들...
}

public class PostCommentSpecification {
    public static Specification<PostComment> hasPostId(Long postId) {
        return (root, query, cb) -> cb.equal(root.get("post").get("id"), postId);
    }

    public static Specification<PostComment> isTopLevelComment() {
        return (root, query, cb) -> cb.isNull(root.get("parentComment"));
    }

    // 추가 Specifications...
}
  • 서비스 레이어에는 이러한 Specification을 결합하여 동적 쿼리를 생성 가능
// 서비스 레이어
List<PostComment> comments = postCommentRepository.findAll(
    where(hasPostId(postId)).and(isTopLevelComment())
);

2. @Query 어노테이션

사용 상황

  • 리포지토리 메서드에 직접 쿼리를 정의하는데 사용된다
  • 메서드 명명 규칙으로 표현하기에 너무 복잡하고, 변경되지 않는 쿼리를 가지고 있을 때 유용 (ex GroupBy 절)

예시

  • 각 상위 레벨 댓글에 대한 답글 수를 세고 싶을 때
public interface PostCommentRepository extends JpaRepository<PostComment, Long>, JpaSpecificationExecutor<PostComment> {

    @Query("SELECT pc.parentComment.commentId, COUNT(pc) " +
            "FROM PostComment pc " +
            "WHERE pc.post.postId = :postId AND pc.parentComment IS NOT NULL " +
            "GROUP BY pc.commentId")
    List<Object[]> countRepliesByPostId(@Param("postId") Long postId);

}

3. 메서드 명명 규칙

사용 상황

  • 메서드 명명 규칙은 Spring Data JPA에서 쿼리를 생성하는 가장 간단한 방법
  • 특정 필드로 모든 레코드를 검색하거나 ID로 레코드를 삭제하는 등의 간단한 쿼리에 최적화

예시

  • 게시물에 대한 모든 상위 레벨 댓글을 찾고 싶을 때
public interface PostCommentRepository extends JpaRepository<PostComment, Long>, JpaSpecificationExecutor<PostComment> {
    List<PostComment> findByPostIdAndParentCommentIsNull(Long postId);
}

이전 포스팅 에서 JPA specification에 대해서 처음 다루어 보았는데, 어떤 상황에 어떤 방법을 사용하면 좋을지를 정리하고 싶어 위 포스팅을 작성하였다✏️✏️ 무조건 specification이나 @Query를 사용하지 말고, 필요한 상황에만 쓸 수 있도록 해야겠다 !!

profile
의견 나누는 것을 좋아합니다 ლ(・ヮ・ლ)

4개의 댓글

comment-user-thumbnail
2024년 1월 31일

좋은 정리네요!

1개의 답글
comment-user-thumbnail
2024년 2월 2일

당신 잠은 잡니까,,

1개의 답글