본문 바로가기
JPA/SpringDataJPA

[SpringDataJPA] 사용자 정의 Repository

by 걸어가는 신사 2022. 6. 4.

사용자 정의 Repository 구현이 필요한 이유

  • 스프링 데이터 JPA 리포지토리는 인터페이스만 정의하고 구현체는 스프링이 자동 생성한다.
  • 메서드를 직접 구현해야 할 때도 있다.
    • JPA 직접 사용 (EntityManager)
    • 스프링 JDBC Template 사용
    • MyBatis 사용
    • 데이터베이스 커넥션 직접 사용
    • Querydsl 사용
  • 하지만 스프링 데이터 JPA가 제공하는 인터페이스를 직접 구현하면 구현해야 하는 기능이 너무 많다.
  • Spring Data JPA는 필요한 메서드만 구현할 수 있는 방법을 제공한다.
  • 다양한 이유로 인터페이스의 메서드를 직접 구현하고 싶다면?

 

사용자 정의 Repository 구현

(1) 사용자 정의 인터페이스 구현

public interface MemberRepositoryCustom {
	List<Member> findMemberCustom();
}
  • 인터페이스 이름은 자유롭게 지으면 된다.

(2) 사용자 정의 인터페이스 구현 클래스

@RequiredArgsConstructor
public class MemberRepositoryImpl implements MemberRepositoryCustom {
    private final EntityManager em;
    @Override
    public List<Member> findMemberCustom() {
        return em.createQuery("select m from Member m")
        .getResultList();
    }
}
  • 규칙 : 리포지토리 인터페이스 이름 + Impl
  • 스프링 데이터 JPA가 인식해서 스프링 빈으로 등록한다.

(3) 사용자 정의 인터페이스 상속

public interface MemberRepository 
	extends JpaRepository<Member, Long>, MemberRepositoryCustom {
}
  • Repository 인터페이스에서 사용자 정의 인터페이스를 상속받는다.

(4) 사용자 정의 메서드 호출 코드

List<Member> result = memberRepository.findMemberCustom();

 

Impl 대신 다른 이름으로 변경하고 싶으면?

  • 두 가지 방법을 소개한다.
  • Impl이 기본값이다.

(1) XML 설정

<repositories base-package="study.datajpa.repository" repository-impl-postfix="Impl" />

(2) JavaConfig 설정

@EnableJpaRepositories(basePackages = "study.datajpa.repository", repositoryImplementationPostfix = "Impl")

참고 : 실무에서는 주로 QueryDSL이나 SpringJdbcTemplate을 함께 사용할 때 사용자 정의 리포지토리 기능을 자주 사용한다.

참고 : 항상 사용자 정의 리포지토리가 필요한 것은 아니다.
그냥 임의의 리포지토리를 만들어도 된다. 예를 들어 MemberQueryRepository를 인터페이스가 아닌 클래스로 만들고 스프링 빈으로 등록해서 그냥 직접 사용해도 된다.
이 경우 스프링 데이터 JPA와는 아무런 관계없이 별도로 동작한다.

 

사용자 정의 리포지토리 구현 최신 방식

스프링 데이터 2.x부터는 사용자 정의 구현 클래스에 리포지토리 인터페이스 이름 + Impl을 적용하는 대신에

사용자 정의 인터페이스 명 + Impl 방식도 지원한다.

예를 들어서 위 예제의 MemberImpl 대신에 MemberRepositoryCustomImpl 같이 구현해도 된다.

@RequiredArgsConstructor
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
    private final EntityManager em;
    @Override
    public List<Member> findMemberCustom() {
        return em.createQuery("select m from Member m").getResultList();
    }
}
  • 기존 방식보다 이 방식이 사용자 정의 인터페이스 이름과 구현 클래스 이름이 비슷하므로 더 직관적이다.
  • 추가로 여러 인터페이스를 분리해서 구현하는 것도 가능하기 때문에 새롭게 변경된 이 방식을 사용하는 것을 더 권장한다.
반응형

댓글