JPA에 대해 알아보자 : 12장 스프링 데이터 JPA

ParkIsComing·2023년 8월 14일

Spring

목록 보기
10/21
post-thumbnail

책 [자바 ORM 표준 JPA 프로그래밍]을 참고하여 작성하였습니다.

Spring Data JPA란

  • Spring 프레임워크에서 JPA를 편리하게 사용할 수 있도록 지원하는 프로젝트이다.
  • CRUD를 처리하기 위한 공통 인터페이스를 제공한다.
  • repository를 개발할 때 인터페이스만 작성하면 실행 시점에 Spring Data JPA가 구현 객체를 동적으로 생성해서 주입해준다.
  • Spring Data Project
    • Spring Data JPA는 Spring Data Project의 하위 프로젝트 중 하나이다.
    • Spring Data Project는 JPA, MongoDB, Redis 같은 다양한 DB에 대한 접근을 추상화한다.

공통 인터페이스 기능

  • save
    • 새로운 엔티티는 저장하고 이미 있는 엔티티는 수정.
    • 식별자 값이 null이면 새로운 엔티티로 판단하여 내부에서 EntityManager.persist() 호출. 아니면 이미 있는 엔티티로 판단해서 EntityManager.merge() 호출.
  • delete
    • 내부에서 EntityManager.remove() 호출
  • fineOne
    • 엔티티 하나 조회
    • 내부에서 EntityManager.find() 호출
  • getOne
    • 엔티티를 프록시로 조회
    • 내부에서 EntityManager.getReference() 호출
  • findAll
    • 모든 엔티티를 조회.
    • Sort나 Pageable 조건을 파라미터로 줄 수 있다.

쿼리 메소드 기능

1) 메서드 이름으로 쿼리 생성

  • 정해진 규칙에 따라 메서드 이름을 작성하면, JPA는 이를 분석해서 자동으로 JPQL을 생성하고 실행한다.




출처 : https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

2) JPA NamedQuery

  • 쿼리에 이름을 부여해서 사용하는 방식
  • 아래와 같이 어노테이션으로 정의하거나 xml에 쿼리를 정의할 수 있다.
  • Spring Data JPA는 도메인 클래스 + .(점) + 메소드 이름으로 Named 쿼리를 찾아서 실행
  • 만약 실행할 Named 쿼리가 없다면 메서드 이름으로 쿼리 생성 전략을 사용
@Entity
@NamedQuery(
	name = "Member.findByUsername",
    query = "select m from Member m where m.username =: username")
public class Member {
	...
}

3) @Query, 리포지토리 메서드에 쿼리 정의

  • 리포지토리 메서드에 직접 쿼리를 정의
  • 장점 : JPA Named 쿼리처럼 애플리케이션 실행 시점에 문법 오류를 발견할 수 있음.
  • 네이티브 SQL를 사용하려면 @Query 애노테이션에 nativeQuery = true를 설정한다.

4) 파라미터 바인딩

  • Spring Data JPA는 위치 기반 파라미터 바인딩과 이름 기반 파라미터 바인딩을 모두 지원
  • 기본값은 위치 기반(파라미터 순서로 바인딩)
  • 이름 기반 파라미터 바인딩을 사용하려면 @Param 애노테이션을 사용
select m from Member m where m.username = ?1 //위치기반
select m from Member m where m.username = :name //이름기반

5) 벌크성 수정 쿼리

  • @Modifyiing 애노테이션으로 벌크성 수정, 삭제 쿼리 사용
  • 벌크성 쿼리 실행 후에 영속성 컨텍스트를 초기화하고 싶으면 @Modifying(clearAutomatically =true)로 설정

6) 반환 타입

  • 결과가 한 건 이상이면 컬렉션 인터페이스(List) 사용, 단건이면 반환타입 지정
  • 조회 결과가 없으면 컬렉션은 빈 컬렉션 반환, 단건이면 null 반환

7) 페이징과 정렬

  • org.springframework.data.domain.Sort : 정렬 기능
  • org.springframework.data.domain.Pageable : 페이징 기능(내부에 Sort 포함)
  • Pageable 파라미터를 설정하면 반환 타입으로 List나 org.springframework.data.domain.Page를 사용할 수 있음
    • Page를 사용하면 페이징 기능을 제공하기 위해 검색된 전체 데이터 건수를 조회하는 count 쿼리를 추가로 호출
  • Pageable은 인터페이스. 따라서 실제 사용할 때는 PageRequest 객체를 사용.
    • 첫번째 파라미터 : 현재 페이지
    • 두번째 파라미터 : 조회할 데이터 수
    • 추가로 Sort 정보도 사용 가능(예: Direction.DESC)
Page<Member> findByName(String name, Pageable pageable);
List<Member> findByName(String name, Pageable pageable);
List<Member> findByName(Stirng name, Sort sort);

PageRequest pageRequest = new PageRequest(0, 10, new Sort(Direction.DESC, "name"));
Page<Member> result = 

8) 힌트

  • @QueryHints : JPA 쿼리 힌트를 위한 애노테이션
@QueryHints(value = { @QueryHint(name = "org.hibernate.readOnly", value = "true")}, forCounting = true)
Page<Member> findByName(String name, Pageable pageable);

9) Lock

@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Member> findByNAme(String name);

사용자 정의 repository 구현

사용자 정의 인터페이스

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

사용자 정의 구현 클래스

public class MemberRepositoryImpl implements MemberRepositoryCustom {
	@Override
    public List<Member> findMemberCustom(){
    	//사용자정의 구현
    }
}

사용자 정의 인터페이스 상속

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

✅실제로 프로젝트에서 Spring Data JPA와 QueryDsl을 함께 사용하기 위해 다음과 같은 방식으로 구현했었다.

WordRepository.java

WordRepositoryCustom.java

WordRepositoryImpl.java

QueryDSL과 Spring Data JPA 통합

QueryDslPredicateExecutor

  • repository에서 QueryDslPredicateExecutor 상속 받아 사용
  • 단점 : join, fetch 사용 불가

QueryDslRepositorySupport

  • QueryDsldsl의 모든 기능을 사용하기 위한 방법
  1. JpaRepository를 상속받는 인터페이스 만들기 (예: MemberRepository)
  2. 커스텀한 메서드를 정의하는 repository 인터페이스를 만들기(예: MemberRepositoryCustom)
  3. MemberRepositoryCustom을 구현, QueryDslRepositorySupport을 상속하는 MemberRepositoryImpl 클래스를 만든다.

1개의 댓글

comment-user-thumbnail
2023년 8월 14일

잘 읽었습니다. 좋은 정보 감사드립니다.

답글 달기