인프런 - 라이프타임 커리어 플랫폼
프로그래밍, 인공지능, 데이터, 마케팅, 디자인등 입문부터 실전까지 업계 최고 선배들에게 배울 수 있는 곳.
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의 마법은 여기서 시작됩니다. 우리는 클래스가 아닌, 인터페이스를 작성하기만 하면 됩니다.
// 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 리포지토리를 서비스에 주입해 보겠습니다.
@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의 핵심 원리입니다.
- 애플리케이션이 시작될 때, 스프링은 JpaRepository를 상속받은 SpringDataJpaMemberRepository 인터페이스를 발견합니다.
- 스프링은 프록시(Proxy) 기술을 사용하여, 이 인터페이스에 대한 가짜 구현 클래스를 런타임에 동적으로 만들어냅니다.
- 이렇게 만들어진 가짜 객체를 실제 스프링 빈으로 컨테이너에 등록합니다.
- 따라서 SpringConfig에서 MemberRepository를 주입해달라고 요청하면, 스프링 컨테이너는 방금 자동으로 생성한 이 프록시 객체를 찾아서 주입해주는 것입니다.
[질문] 프록시(Proxy)와 인젝션(Injection)이란?
- 프록시(Proxy): '대리인'이라는 뜻입니다. 스프링 데이터 JPA가 만든 가짜 구현 객체(프록시)는, save()와 같은 메소드가 호출되면 그 요청을 가로채서 실제 JPA 로직(EntityManager 호출 등)을 대신 수행하고 결과를 반환해주는 대리인 역할을 합니다.
- 인젝션 해서 사용: '주입해서 사용한다'는 의미입니다. 내가 직접 new로 객체를 만드는 것이 아니라, 필요한 객체를 생성자의 파라미터 등으로 선언만 해두면 스프링 컨테이너가 알아서 해당 객체를 **'주입(연결)'**해주는 방식을 말합니다.
## 4. 스프링 데이터 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를 보조적으로 사용하는 경우가 많습니다.
'개발 공부 > 백엔드' 카테고리의 다른 글
| REST API, 개념부터 설계 원칙까지 한 번에 이해하기 (0) | 2025.10.03 |
|---|---|
| AOP로 공통 관심 사항 깔끔하게 분리하기 (1) | 2025.10.02 |
| 스프링 DB 접근 기술 : 3. JPA (0) | 2025.09.29 |
| 스프링 DB 접근 기술 : 2. JdbcTemplate (0) | 2025.09.27 |
| DB까지 연결하는 통합 테스트 (0) | 2025.09.27 |