16. 스프링 데이터 JPA
스프링 데이터 JPA는 스프링과 JPA를 통합해서 사용하는 방식이다.
스프링 데이터 JPA를 이용하면 코드의 반복 작업과 DB 연동 구현에 들이는 시간을 정말 획기적으로 줄일 수 있다.
스프링 데이터 JPA는 여러 어플리케이션에서 자주 사용하는 CRUD 기능을 제공하여 반복 작업을 줄여주어,
개발자가 핵심 비즈니스 로직에 집중할 수 있도록 돕는다.
직접 해보면 대단하긴 하다. 할 게 거의 없다.
단, 스프링 데이터 JPA는 JPA를 쉽게 사용할 수 있도록 돕는 기술이기 때문에, JPA에 대한 이해 없이 사용하면 의미가 없다.
환경설정
JPA와 같은 환경으로 설정한다.
스프링 데이터 JPA 리포지토리 생성 및 적용
SpringDataJpaMemberRepository 인터페이스를 생성한다.
SpringDataJpaMemberRepository.java
package hdxian.hdxianspring.repository;
import hdxian.hdxianspring.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
@Override
Optional<Member> findByName(String name);
}
JPA 라이브러리에 있는 JpaRepository, 지금까지 사용하던 MemberRepository를 상속한 SpringDataJpaMemberRepository 인터페이스를 생성한다.
이러면 끝이다. 구현 클래스를 작성할 필요가 없다.
JpaRepository를 상속한 인터페이스를 생성하면, 스프링 구동 시 자동으로 해당 인터페이스의 구현 객체가
스프링 컨테이너에 등록된다. SpringConfig에서 MemberService가 그 구현 객체를 인젝션 받도록 하면 된다.
스프링 데이터 JPA 리포지토리를 사용하도록 SpringConfig를 변경한다.
SpringConfig.java
package hdxian.hdxianspring;
import hdxian.hdxianspring.repository.*;
import hdxian.hdxianspring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
@Configuration
public class SpringConfig {
// private final DataSource dataSource;
// private final EntityManager em;
// public SpringConfig(DataSource dataSource, EntityManager em) {
// this.dataSource = dataSource;
// this.em = em;
// }
private final MemberRepository memberRepository;
@Autowired
public SpringConfig(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Bean
public MemberService memberService() {
return new MemberService(memberRepository);
}
// @Bean
// public MemberRepository memberRepository() {
//// return new MemoryMemberRepository()
//// return new JdbcMemberRepository(dataSource);
//// return new JdbcTemplateMemberRepository(dataSource);
//// return new JpaMemberRepository(em);
// }
}
주석 처리한 부분은 이전 코드와의 차이를 구분하기 위해 남겨둔 것이다. 다 지워도 상관 없다.
JpaRepository 인터페이스
jpa 라이브러리에서 제공하는 JpaRepository 인터페이스의 코드를 보면, findById(), findAll() 등의 메서드가 미리 정의되어 있는것을 확인할 수 있다.
여러 어플리케이션에서 비슷하게 쓰이는 기능들을 미리 정의해놓고, 인터페이스로 상속하기만 하면 해당 기능들을 알아서 구현해주는 원리다.
JPA 또는 스프링 데이터 JPA는 그 내용만으로 따로 강의가 나올 정도로 내용이 방대하기 때문에,
지금 단계에서는 자세히 알지 못한다.
하지만 분명한 점은, 이러한 간단한 기능들은 스프링 데이터 JPA를 통해 쉽게 구현할 수 있고,
따라서 개발자는 절약된 시간만큼 핵심 비즈니스 로직 구현에 집중할 수 있으므로 개발 생산성을 크게 향상시킬 수 있다.
(당연히 복잡한 쿼리나 로직은 별도로 개발자가 작성해야 한다. 스프링 데이터 JPA는 그것에 집중할 수 있도록 돕는 것.)
+)
SpringDataJpaMemberRepository.java에서 findByName()만 따로 Override한 이유는,
앞서 설명한 JpaRepository 인터페이스에 미리 정의되어있지 않은 메서드이기 때문이다.
프로그램마다 비즈니스 로직이 다르므로 당연히 모든 메서드를 미리 정의해놓을 수는 없다.
따라서 JpaRepository 인터페이스에 미리 정의되어있지 않은 메서드는 findBy~ 와 같은 특수한 명명 규칙에 따라 메서드를 정의하면 거기에 맞게 스프링 데이터 JPA가 sql 쿼리를 생성해 DB와 연동해준다.
다음은 스프링 데이터 JPA의 대략적인 구성이다.
솔직히 봐도 잘 이해가 안된다. 자세한 내용은 후에 자세히 배울 듯 싶다. 지금은 개념만 이해하고 넘어가겠다.