개발 공부/백엔드

스프링 DB 접근 기술 : 4. 스프링 데이터 JPA

baby-t 2025. 9. 29. 13:09

https://www.inflearn.com/

 

인프런 - 라이프타임 커리어 플랫폼

프로그래밍, 인공지능, 데이터, 마케팅, 디자인등 입문부터 실전까지 업계 최고 선배들에게 배울 수 있는 곳.

www.inflearn.com

인프런 사이트의 김영한님의 강의를 보면서 작성한 글입니다.

 

이전 포스팅에서는 JdbcTemplate을 사용하여 반복적인 JDBC 코드를 제거했습니다. 하지만 여전히 SQL 쿼리는 개발자가 직접 작성해야 했습니다.

이번 포스팅에서는 현대적인 Java 웹 개발의 표준인 **스프링 데이터 JPA(Spring Data JPA)**를 도입하여, 리포지토리 계층을 인터페이스만으로 완성하는 놀라운 경험을 해보겠습니다. ✨

주의: 스프링 데이터 JPA는 JPA를 편리하게 사용하도록 도와주는 도구이므로, JPA에 대한 기본적인 학습 후에 사용하는 것을 권장합니다.


## 1. 스프링 데이터 JPA 설정

JPA 설정은 이전 포스팅과 거의 동일합니다. build.gradle에 spring-boot-starter-data-jpa 의존성이 있는지, application.properties에 DB 접속 정보와 JPA 설정이 있는지 확인합니다.


## 2. 리포지토리 인터페이스 작성

스프링 데이터 JPA의 마법은 여기서 시작됩니다. 우리는 클래스가 아닌, 인터페이스를 작성하기만 하면 됩니다.

Java
 
// SpringDataJpaMemberRepository.java
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
    
    // 이전에 MemberRepository에 정의했던 findByName을 Spring Data JPA가 규칙에 맞게 구현해준다.
    @Override
    Optional<Member> findByName(String name);
}
  • extends JpaRepository<Member, Long>: 이 부분이 핵심입니다. JpaRepository를 상속받으면, 스프링 데이터 JPA가 해당 인터페이스의 구현체를 동적으로 생성하여 스프링 빈으로 자동 등록해 줍니다. <Member, Long>은 이 리포지토리가 Member 엔티티를 다루고, 해당 엔티티의 PK 타입이 Long임을 의미합니다.

## 3. SpringConfig와 의존관계 주입의 원리

이제 SpringConfig 파일을 수정하여, 새로 만든 스프링 데이터 JPA 리포지토리를 서비스에 주입해 보겠습니다.

Java
 
@Configuration
public class SpringConfig {

    private final MemberRepository memberRepository;

    @Autowired // 생성자가 하나일 경우 생략 가능
    public SpringConfig(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository);
    }
}

[질문] MemberRepository의 구현 클래스를 만든 적이 없는데 어떻게 주입이 되나요?

이것이 바로 스프링 데이터 JPA의 핵심 원리입니다.

  1. 애플리케이션이 시작될 때, 스프링은 JpaRepository를 상속받은 SpringDataJpaMemberRepository 인터페이스를 발견합니다.
  2. 스프링은 프록시(Proxy) 기술을 사용하여, 이 인터페이스에 대한 가짜 구현 클래스를 런타임에 동적으로 만들어냅니다.
  3. 이렇게 만들어진 가짜 객체를 실제 스프링 빈으로 컨테이너에 등록합니다.
  4. 따라서 SpringConfig에서 MemberRepository를 주입해달라고 요청하면, 스프링 컨테이너는 방금 자동으로 생성한 이 프록시 객체를 찾아서 주입해주는 것입니다.

[질문] 프록시(Proxy)와 인젝션(Injection)이란?

  • 프록시(Proxy): '대리인'이라는 뜻입니다. 스프링 데이터 JPA가 만든 가짜 구현 객체(프록시)는, save()와 같은 메소드가 호출되면 그 요청을 가로채서 실제 JPA 로직(EntityManager 호출 등)을 대신 수행하고 결과를 반환해주는 대리인 역할을 합니다.
  • 인젝션 해서 사용: '주입해서 사용한다'는 의미입니다. 내가 직접 new로 객체를 만드는 것이 아니라, 필요한 객체를 생성자의 파라미터 등으로 선언만 해두면 스프링 컨테이너가 알아서 해당 객체를 **'주입(연결)'**해주는 방식을 말합니다.

## 4. 스프링 데이터 JPA가 제공하는 놀라운 기능들

스프링 데이터 JPA 인터페이스 (김영한님)

### 1. 기본 CRUD 기능 자동 제공

JpaRepository 인터페이스에는 save(), findById(), findAll(), delete() 등 기본적인 CRUD 메소드가 이미 모두 정의되어 있습니다. 우리는 그저 상속받는 것만으로 이 모든 기능을 바로 사용할 수 있습니다.

### 2. 쿼리 메소드 기능

스프링 데이터 JPA의 가장 강력한 기능 중 하나로, 메소드 이름만으로 쿼리를 자동으로 생성합니다.

  • findByName(String name): name 필드를 기준으로 SELECT 쿼리를 자동 생성합니다.
  • findByNameAndId(String name, Long id): name과 id를 모두 조건으로 하는 AND 쿼리를 생성합니다.

다양한 규칙은 공식 문서를 참고하면 되며, 이를 통해 간단한 조회 기능은 SQL 작성 없이 메소드 선언만으로 끝낼 수 있습니다.

[질문] 기존 MemberRepository 인터페이스 없이 바로 사용해도 되나요?

네, 가능합니다. 하지만 실무에서는 MemberRepository처럼 핵심 비즈니스 로직에 필요한 메소드를 먼저 인터페이스로 정의하고, SpringDataJpaMemberRepository가 이 인터페이스를 extends 하도록 설계하는 것이 좋습니다. 이는 향후 스프링 데이터 JPA가 아닌 다른 기술로 리포지토리를 교체해야 할 때, 서비스 계층의 코드 변경을 최소화하는 좋은 객체 지향 설계입니다.

### 3. 페이징 기능 자동 제공

데이터베이스 페이징 처리를 매우 간단하게 구현할 수 있는 기능을 기본으로 제공합니다.


## 5. 실무에서의 활용

스프링 데이터 JPA는 대부분의 정형화된 데이터 처리를 매우 간단하게 만들어주지만, 복잡한 통계 쿼리 등 동적 쿼리를 처리하는 데는 한계가 있습니다.

실무에서는 이러한 복잡한 동적 쿼리를 처리하기 위해 Querydsl이라는 라이브러리를 함께 사용하거나, 필요에 따라 JdbcTemplate이나 MyBatis를 보조적으로 사용하는 경우가 많습니다.