Skip to content

Latest commit

 

History

History
156 lines (96 loc) · 6.57 KB

12장.md

File metadata and controls

156 lines (96 loc) · 6.57 KB

스프링 데이터 JPA

public class MemberRepository {

    @PersistenceContext
    public EntityManager em;

    public void save() {...}

    public Member findOne(Long id) {...}

    public List<Member> findAll() {...}

    public Member findByUsername(String username) {...}
}

JPA를 사용해도 대부분의 데이터 접근 계층은 CRUD라고 하는 코드를 반복해서 개발해야 하는 문제점이 존재합니다. 이러한 단점을 해결하기 위해 나온 것이 Spring Data JPA 입니다.



Spring Data JPA 소개

Spring Data JPA는 스프링 프레임워크에서 JPA를 편리하게 사용할 수 있도록 지원하는 프로젝트입니다. 데이터 접근 계층을 개발할 때 위에서 보았던 단순하고 반복적인 CRUD 작업들을 멋지게 해결합니다. 레포지토리를 개발할 때 인터페이스만 작성하면 실행 시점에 Spring Data JPA가 구현 객체를 동적으로 생성해서 주입해줍니다.

따라서 위의 코드처럼 하나하나 작성하지 않고, 구현 클래스 없이 인터페이스만 작성해도 개발을 완료할 수 있습니다.

public interface MemberRepository extends JpaRepository<Member, Long> {
    Member findByUsername(String username);
}

즉, CRUD를 처리하기 위한 공통 메소든느 Spring Data JPA가 제공하는 org.springframework.data.jpa.repository.JpaRepository 인터페이스에 있습니다. 인터페이스의 구현체는 애플리케이션 실행 시점에 Spring Data JPA가 생성해서 주입해줍니다.

일반적인 CRUD 메소드는 JpaRepository에서 제공해주지만, 위의 보이는 findByUsername와 같이 공통으로 처리할 수 없는 메소드는 개발자가 직접 작성해야 하는데요. Spring Data JPA는 메소드 이름을 분석해서 아래와 같은 JPQL을 만들어줍니다.

SELECT m FROM Member m WHERE username =:username



Spring Data JPA 프로젝트

스크린샷 2021-11-10 오후 3 44 37

Spring Data 프로젝트는 JPA, MongoDB, NEO4J, Redis, HADDOP, GEMFIRE 같은 다양한 데이터 저장소에 대한 접근을 추상화해서 개발자 편의를 제공하고 지루하게 반복하는 데이터 접근 코드를 줄여줍니다.



공통 인터페이스 기능

Spring Data JPA는 간단한 CRUD 기능을 공통으로 처리하는 JpaRepository 인터페이스를 제공합니다.

스크린샷 2021-11-10 오후 3 55 48

JpaRepository 인터페이스의 계층 구조는 위와 같습니다. 위의 그림을 보면 CrudRepository 부터 Spring Data 영역이고 그 아래부터는 Spring Data JPA 영역입니다.

  • save(S): 새로운 엔티티는 저장하고 이미 있는 엔티티는 수정합니다.
  • delete(T): 엔티티 하나를 삭제합니다. 내부에서 EntityManager.remove()를 호출합니다.
  • findOne(ID): 엔티티 하나를 조회합니다. 내부에서 EntityManager.find()를 호출합니다.
  • getOne(ID): 엔티티를 프록시로 조회합니다. 내부에서 EntityManager.getReference()를 호출합니다.
  • findAll(...): 모든 엔티티를 조회합니다. 정렬이나 페이징 조건을 파라미터로 제공할 수 있습니다.

위의 메소드는 JpaRepository를 상속받으면 사용할 수 있는 주요 메소드 몇 가지를 정리하였습니다.



Query Method 기능

쿼리 메소드 기능은 Spring Data JPA가 제공하는 마법 같은 기능입니다.

  • 메소드 이름으로 쿼리 생성
  • 메소드 이름으로 JPA NamedQuery 호출
  • @Query 애노테이션을 사용해서 레포지토리 인터페이스에 쿼리 직접 정의

Spring Data JPA가 제공하는 쿼리 메소드 기능은 크게 3가지가 있습니다. 하지만 여기서는 1, 3번 두 가지만 알아보겠습니다.



메소드 이름으로 쿼리 생성

public interface MemberRepository extends JpaRepository<Member, Long> {
    List<Member> findByEmailAndName(String email, String name);
}

인터페이스에 정의한 findByEmailAndName 메소드를 실행하면 Spring Data JPA는 메소드 이름을 분석해서 JPQL을 생성하고 실행합니다.

SELECT m FROM Member m WHERE m.email = ?1 and m.name = ?2

실행되는 JPQL은 위와 같습니다.



@Query Repository 메소드에 쿼리 정의

public interface MemberRepository extends JpaRepository<Member, Long> {

    @Query("select m from Member m where m.username = ?1")
    Member findByEmailAndName(String username);
}

위와 같이 리포지토리 메소드에 직접 쿼리를 정의하려면 @Query 애노테이션을 사용하면 됩니다. 이 방법은 실행할 메소드에 정적 쿼리를 직접 작성하므로 이름 없는 Named 쿼리라도 가능합니다.


네이티브 쿼리 작성

public interface MemberRepository extends JpaRepository<Member, Long> {

    @Query("select m from Member m where m.username = ?1", nativeQuery = ture)
    Member findByEmailAndName(String username);
}

위와 같이 nativeQuery = true를 설정하면 Native SQL을 사용할 수 있습니다.



페이징과 정렬

Spring Data JPA는 쿼리 메소드에 페이징과 정렬 기능을 사용할 수 있도록 2가지 특별한 파라미터를 제공합니다.

  • org.springframework.data.domain.Sort: 정렬 기능
  • org.springframework.data.domain.Pageable: 페이징 기능

Pageable을 사용하면 반환 타입으로 List나 Page를 사용할 수 있습니다.


// Count 쿼리 사용
Page<Member> findByName(String name, Pageable pageable);

// count 쿼리 사용 안 함
List<Member> findByName(String name, Pageable pageable)

List<Member> findByName(String name, Sort sort);

위와 같이 반환 타입을 Page를 사용하면 페이징 기능을 제공하기 위해 검색된 전체 데이터 건수를 조회하면 count 쿼리를 추가로 호출합니다. Spring Data JPA에서 페이징을 사용하는 방법에 대해서 정리는 다른 글에서 하였는데 궁금하다면 여기 에서 확인할 수 있습니다.