본문 바로가기
Backend/JPA

JPA (Spring Data JPA) - 사용자 정의 리포지토리 개념과 구현 방법

by 개발자-제이 2025. 3. 12.
반응형

 

1. Spring Data JPA 기본 리포지토리

Spring Data JPA에서는 JpaRepository 인터페이스를 상속받으면 자동으로 구현체가 생성된다. 기본적인 CRUD 메서드는 JpaRepository에서 제공하기 때문에 별도로 구현할 필요가 없다.

public interface MemberRepository extends JpaRepository<Member, Long> {
}

이렇게 하면 findById, save, delete 같은 기본적인 데이터 조작 메서드를 사용할 수 있다. 하지만 복잡한 쿼리, 특정 조건을 기반으로 한 데이터 조회, 또는 커스텀 로직을 추가하려면 직접 구현해야 다.

 

2. 사용자 정의 리포지토리 필요성

기본 JpaRepository만으로는 다음과 같은 경우를 해결할 수 없다.

  • 복잡한 쿼리 실행: 단순 조회가 아니라 JOIN, GROUP BY, 동적 조건 추가가 필요할 때
  • JPA의 EntityManager 직접 사용: JPA의 고급 기능을 활용하거나 네이티브 쿼리를 실행할 때
  • Spring JDBC Template 사용: JPA 대신 JDBC를 활용해야 할 때
  • MyBatis 사용: MyBatis를 통해 SQL 기반으로 데이터 조회해야 할 때
  • QueryDSL 사용: 동적 쿼리를 쉽게 관리하기 위해 QueryDSL을 적용해야 할 때

이런 경우에는 사용자 정의 리포지토리를 활용해서 직접 원하는 메서드를 구현할 수 있다.

 

3. 사용자 정의 리포지토리 동작 방식

Spring Data JPA에서 사용자 정의 리포지토리를 만들면 JPA의 기본 기능과 사용자 정의 기능을 동시에 사용할 수 있다. 

Spring이 사용자 정의 구현을 인식하는 방식은 다음과 같다.

  1. 사용자 정의 리포지토리 인터페이스 생성 (MemberRepositoryCustom)
  2. 사용자 정의 리포지토리 구현 클래스 생성 (MemberRepositoryImpl)
  3. 기본 JPA 리포지토리에 사용자 정의 리포지토리 인터페이스를 추가 (MemberRepository)

이 과정을 통해 Spring은 MemberRepository의 기본 CRUD 기능과 함께 사용자 정의 메서드도 자동으로 주입할 수 있다.

 

4. 사용자 정의 리포지토리 인터페이스

먼저 사용자 정의 기능을 제공할 인터페이스를 만든다.

public interface MemberRepositoryCustom {
    List<Member> findMemberCustom();
}

이 인터페이스는 JPA에서 기본적으로 제공하는 메서드 외에 추가로 제공하고 싶은 기능을 정의하는 곳이다.

 

5. 사용자 정의 리포지토리 구현

import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class MemberRepositoryImpl implements MemberRepositoryCustom {

    private final EntityManager em;

    @Override
    public List<Member> findMemberCustom() {
        return em.createQuery("select m from Member m", Member.class)
                 .getResultList();
    }
}

 

  • EntityManager를 사용해 직접 JPQL을 실행
  • @RequiredArgsConstructor를 사용해 EntityManager의 의존성 자동 주입

 

6. 기존 JPA 리포지토리와 통합

 

public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {
}

 

  • 이와 같이 사용하면, JpaRepository에서 제공하는 기본 CRUD 기능과
  • MemberRepositoryCustom에서 정의한 추가 메서드를 함께 사용할 수 있다.

 

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

 

Spring Data JPA 2.x부터 Impl 대신 CustomImpl을 사용할 수 있다

@RequiredArgsConstructor
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
    private final EntityManager em;

    @Override
    public List<Member> findMemberCustom() {
        return em.createQuery("select m from Member m", Member.class)
                 .getResultList();
    }
}

이 방식의 장점:

  • 직관적인 네이밍 (CustomImpl)
  • 유지보수 용이

 

8. 사용자 정의 리포지토리 활용 예제

특정 조건을 만족하는 회원 조회

@Override
public List<Member> findActiveMembers() {
    return em.createQuery("SELECT m FROM Member m WHERE m.status = 'ACTIVE'", Member.class)
             .getResultList();
}

네이티브 쿼리 실행

@Override
public List<Member> findByCustomNativeQuery() {
    return em.createNativeQuery("SELECT * FROM member WHERE age > 30", Member.class)
             .getResultList();
}

 

 

9. 정리

  • Spring Data JPA는 기본 CRUD 제공
  • 복잡한 쿼리는 사용자 정의 리포지토리로 해결
  • CustomImpl을 사용하면 유지보수가 쉬움
  • JPA의 EntityManager, QueryDSL, 네이티브 쿼리까지 활용 가능
반응형