[Spring Boot, JPA] Repository와 JpaRepository, 어떤 것을 선택할까?

Jeongyeon Park·2023년 12월 30일
0

Spring 개념 정리

목록 보기
4/4

들어가며

MyBatis 기반으로 작성된 DAO 코드를 JPA Repository로 변경하는 과정에서, @Repository 어노테이션 사용(stereotype) / JpaRepository / CrudRepository / Repository 인터페이스 상속 (Spring Data JPA) 중 어느 것을 선택해야 하는지 고민하게 되었습니다.

이전까지는 기계적으로 JpaRepository 인터페이스를 상속받아 사용했기 때문에, 이번 기회에 정확한 차이점을 알아보고자 합니다.

이 글은 개인적으로 공부하며 이해한 내용을 정리한 것으로, 부정확한 정보가 있는 경우 댓글로 피드백 주시면 감사하겠습니다.

@Repository (stereotype)

Persistence Layer 역할을 하는 class에 사용하는 어노테이션으로, 해당 class를 루트 컨테이너에 Bean으로 생성&등록하고 핸들러가 스캔할 수 있도록 합니다.


@Repository
public class MemberRepository {

    private final EntityManager em;
    
    public void register(Member member) {
    	em.persist(member);
        em.merge(member);
    }
}

내부 코드는 다음과 같습니다.

@Component 어노테이션을 포함하므로, Classpath Scanning 과정에서 자동으로 루트 컨테이너에 등록될 수 있습니다.


Repository Interfaces

JPA를 사용할 때, Repository에서 일반적으로 상속받는 인터페이스에는 Repository, CrudRepository, PagingAndSortingRepository, JpaRepository 등이 있습니다.

Repository, CrudRepository, PagingAndSortingRepository는 Spring Data Project에서 공통적으로 사용할 수 있는 인터페이스이고, JpaRepository는 Spring Data JPA에서 제공하는 인터페이스입니다.

Repository가 최상위 인터페이스이고, 아래쪽으로 갈수록 상위 인터페이스를 상속하여 정의한 구현체이며 더 많은 기능을 제공합니다.

각 인터페이스에서 제공하는 기능을 간단하게 정리하면 다음과 같습니다.

  • CrudRepository | CRUD 관련 기능 (select, insert, update, delete)

  • PagingAndSortingRepository | CRUD 관련 기능 + Paging 및 Sorting 관련 기능

  • JpaRepository | CRUD 관련 기능 + Paging 및 Sorting 관련 기능 + JPA 관련 특화기능 (Flushing 및 Batch 작업 등)


Repository Interface 내부 코드

그렇다면 각 인터페이스에는 구체적으로 어떤 차이가 있는지, 코드를 통해 알아보겠습니다.

Repository

Repository는 최상위 인터페이스로, Domain (or Entity)의 타입과 ID(PK) 타입을 받는 역할을 합니다. Repository의 특징은 다음과 같습니다.

  • 기본적으로 구현되어 있는 메서드가 없으므로, 인터페이스를 상속받은 곳(ex. UserRepository)에서 사용할 메서드를 직접 선언해야 한다.

  • 선언된 메서드만 외부에 개방되므로, 각 레포지토리의 역할과 책임을 명확하게 표현할 수 있다.


CrudRepository

CrudRepository는 Repository를 상속받은 인터페이스로, Repository의 역할(Domain & ID 타입 저장)과 함께 CRUD 기능을 제공합니다. CrudRepository의 특징은 다음과 같습니다.

  • @NoRepositoryBean => CrudRepository는 Repository를 상속받는 구현체이지, 그 자체로 Repository Layer의 역할을 하지는 않는다. 따라서, Spring에서 CrudRepository를 Bean으로 등록하는 것을 방지하기 위해 해당 어노테이션을 사용한다. (@Repository 어노테이션을 사용해도 무시됨)

  • select, insert, update, delete, count에 대응되는 작업을 수행하는 메서드들이 선언되어 있다.

  • (CrudRepository를 상속받은) 레포지토리에서 별도의 메서드 선언을 하지 않아도, CrudRepository 내부에 선언된 메서드를 외부(Service Layer 등)에서 호출할 수 있다.


PagingAndSortingRepository

PagingAndSortingRepository는 Repository를 상속받은 인터페이스로, Repository의 역할과 함께 Paging과 Sorting 관련 기능을 제공합니다. PagingAndSortingRepository의 특징은 다음과 같습니다.

  • @NoRepositoryBean

  • select * from domain 쿼리의 결과를 주어진 sort 조건에 따라 정렬하여 리턴한다.

  • select * from domain 쿼리의 결과를 주어진 paging 조건에 따라 pagination 된 상태로 리턴한다.

  • 레포지토리에서 별도의 메서드 선언을 하지 않아도, PagingAndSortingRepository 내부에 선언된 메서드를 외부에서 호출할 수 있다.


JpaRepository

JpaRepository는 CrudRepository와 PagingAndSortingRepository를 상속받은 인터페이스로, CrudRepository, PagingAndSortingRepository의 역할과 함께 Flush, Batch 관련 기능을 제공합니다. JpaRepository의 특징은 다음과 같습니다.

  • @NoRepositoryBean

  • Flush - Persistence Context(영속성 컨텍스트)의 변경 내용을 DB 테이블에 실제로 반영하는 기능을 제공한다.

  • Batch - 여러 개의 SQL Statement를 하나의 그룹으로 묶어서 한 번에 처리하는 기능을 제공한다.

  • 레포지토리에서 별도의 메서드 선언을 하지 않아도, JpaRepository 내부에 선언된 메서드를 외부에서 호출할 수 있다.

Flush와 Batch에 관한 자세한 설명은 별도의 포스팅에서 다루겠습니다.

최종 선택

선택을 위해 고려한 프로젝트의 특징은 다음과 같습니다.

  • 서비스의 비즈니스 로직 상, 쿼리는 대부분 기본적인 CRUD 기능을 수행하고 있습니다. Join, Subquery 등 커스텀이 필요한 쿼리가 많이 존재하지 않으므로, 이미 JpaRepository에서 제공되는 메서드들을 하나하나 직접 선언하는 것은 불필요하다고 생각했습니다.

  • 키워드 기준 검색, 제목 기준 검색, 장소 기준 검색 등의 구현을 위해 select 쿼리가 많이 사용되는데, Repository를 사용하는 경우 select a, b from table where c = "qwerty" / select b, c from table where a = "oiuy" 등 유사한 포맷의 쿼리를 반복해서 작성해야 하는 번거로움이 있을 것이라고 생각했습니다.

위와 같은 이유로, JpaRepository를 상속받아 사용하기로 결정했습니다.



+ @EnableJpaRepositories

Spring Data Project에서 제공하는 Reposiory 인터페이스를 사용하면, @Repository 어노테이션을 추가적으로 선언해주지 않아도 해당 레포지토리가 Bean으로 등록됩니다.

이러한 작업이 가능한 것은, Spring Boot에서 기본적으로 @EnableJpaRepositories가 설정되어 있기 때문입니다.

위 코드에서 실질적으로 레포지토리를 Bean으로 등록하는 역할을 하는 부분은 @Import의 JpaRepositoriesRegistrar.class 입니다.

JpaRepositoriesRegistrar는 다시 ImportBeanDefinitionRegistrar을 상속받습니다.

Annotation metadata를 받아 JpaRepository를 Bean으로 등록합니다.


References

0개의 댓글

관련 채용 정보