본문 바로가기

스터디/JPA

스프링 데이터 JPA - (1)

728x90
반응형

스프링 데이터 JPA 소개


스프링 프레임워크에서 JPA를 편리하게 사용할 수 있도록 지원하는 프로젝트이다

 

CRUD 처리를 위한 인터페이스를 제공해 리포지토리 개발 시 인터페이스만 작성하면 실행 시점에 스프링 데이터 JPA가 구현 객체를 동적으로 생성해서 주입해준다

데이터 접근 계층을 개발할 때 구현 클래스 없이 인터페이스만 작성해도 개발을 완료할 수 있다

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

 

JPA는 메소드 이름을 분석해 JPQL을 실행해준다

스프링 데이터 프로젝트

스프링 데이터 JPA는 스프링 데이터 프로젝트의 하위 프로젝트 중 하나이다

 

스프링 데이터 프로젝트 다양한 데이터 저장소에 대한 접근을 추상화해 개발자 편의를 제공하고 반복되는 데이터 접근 코드를 줄여준다

 

스프링 데이터 JPA 프로젝트는 JPA에 특화된 기능을 제공한다 (사용 추천)

공통 인터페이스 기능


 

JpaRepository를 상속받고 제네릭에 엔티티 클래스와 엔티티 클래스가 사용하는 식별자 타입을 지정해 사용한다

 

스프링 데이터 모듈에는 Repository, CrudRepository, PagingAndSortingRepository가 있는데 이는 스프링 데이터 프로젝트가 공통적으로 사용하는 인터페이스이다

스프링 데이터 JPA가 제공하는 JpaRepository는 여기에 추가로 JPA에 특화된 기능을 제공한다

 

 

JpaRepository를 상속받으면 쓸 수 있는 주요 메소드

 

- save(S): 새로운 엔티티는 저장하고 이미 있는 엔티티는 수정한다

- delete(T): 엔티티 하나를 삭제한다

- findOne(ID): 엔티티 하나를 조회한다

- getOne(ID): 엔티티를 프록시로 조회한다 (EntityManger.getReference())

- findAll(…): 모든 엔티티를 조회한다. 정렬이나 페이징 조건을 파라미터로 제공할 수 있다

쿼리 메소드 기능


1. 메소드 이름으로 쿼리 생성

JPA는 메소드 이름을 분석해 JPQL을 생성하고 실행한다

 

엔티티의 필드 명이 변경되면 인터페이스에 정의한 메소드 이름도 함께 변경해야 한다

2. JPA NamedQuery

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

메소드 이름만으로 NamedQuery를 호출 할 수 있어서 JPA에서 직접 호출하는 것에 비해 간단하게 사용할 수 있다

 

스프링 데이터 JPA는 먼저 (도메인 클래스.메소드 이름)으로 Named 쿼리를 찾아서 실행하고 없다면 메소드 이름으로 쿼리 생성 전략을 사용한다

3. @Query, 리포지토리 메소드에 쿼리 정의

@Query를 사용해 리포지토리 메소드에 직접 쿼리를 정의할 수 있다

 

실행할 메소드에 정적 쿼리를 직접 작성하므로 이름 없는 Named 쿼리라 할 수 있다

Named 쿼리 처럼 실행 시점에 문법 오류를 발견할 수 있다

 

네이티브 SQL을 사용하려면 nativeQuery를 true로 설정하면된다

JPQL과 다르게 위치 기반 파라미터 사용 시 0부터 시작한다

파라미터 바인딩

스프링 데이터 JPA는 위치 기반 파라미터 바인딩과 이름 기반 파라미터 바인딩을 모두 지원한다

기본 값은 위치 기반으로 파라미터 순서로 바인딩한다

 

이름 기반 파라미터 바인딩을 사용하려면 @Param 어노테이션을 사용하면된다

가독성과 유지보수를 위해 이름 기반 파라미터 바인딩을 사용하는 것이 좋다

벌크성 수정 쿼리

@Modifying
@Query("update Product p set p.price = p.price*1.1 where p.stockAmount < :stockAmount")
int bulkPriceUp(@Param("stockAmount") String stockAmount);

JPA에서 벌크성 수정, 삭제 쿼리는 @Modifying 어노테이션을 사용한다

 

벌크성 쿼리를 실행한 후 영속성 컨텍스트를 초기화하려면 clearAutomatically 옵션을 true로 설정하면 된다

반환 타입

결과가 한 건 이상이면 컬렉션 인터페이스를 사용하고, 단건이면 반환 타입을 지정한다

List<Member> findByName(String name);
Member findByEmail(String email);

 

조회 결과가 없는 경우 각각 빈 컬렉션과 null을 반환한다

반환 타입을 지정했는데 결과가 2건 이상이면 NoUniqueResultException 예외가 발생한다

페이징과 정렬

파라미터에 Pageable을 사용하면 반환 타입으로 List나 Page를 사용할 수 있다

 

Page를 사용하면 JPA는 페이징 기능을 제공하기 위해 검색된 전체 데이터 건수를 조회하는 count 쿼리를 추가로 호출한다

public interface MemberRepository extends Repository<Member, Long> {
	
		Page<Member> findByNameStartingWith(String name, Pageable pageable);
}

 

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

List<Member> members = result.getContent(); //조회된 데이터
int totalPages = result.getTotalPages(); //전체 페이지 수
boolean hasNextPage = result.hasNextPage(); //다음 페이지 존재 여부

Pageable은 인터페이스로 실제 사용할 때에는 Pageable을 구현한 PageRequest 객체를 사용한다

 

PageRequest를 생성할 때는 파라미터로 현재 페이지, 조회할 데이터 수를 넘겨준다

추가적으로 정렬 정보도 파라미터로 사용할 수 있다

 

Page 인터페이스는 다양한 메소드를 제공한다

힌트

@QueryHints를 사용해 JPA 구현체에게 쿼리 힌트를 제공할 수 있다

 

@QueryHints(value = { @QueryHint(name="org.hibernate.readOnly",
	value="true")}, forCounting=true)
Page<Member> findByName(String name, Pageable pageable)

forCounting 속성은 반환타입으로 Page 인터페이스를 적용하면 추가로 호출하는 페이징을 위한 count 쿼리에도 쿼리 힌트를 적용할지 설정하는 옵션이다 (기본값 true)

Lock

@Lock을 사용해 쿼리 시 락을 걸 수 있다

@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Member> findByName(String name);
728x90
반응형

'스터디 > JPA' 카테고리의 다른 글

웹 애플리케이션과 영속성 관리 - (1)  (0) 2025.03.20
스프링 데이터 JPA - (2)  (0) 2025.02.20
객체지향 쿼리 언어 - (7)  (1) 2025.02.19
객체지향 쿼리 언어 - (6)  (0) 2025.02.19
객체지향 쿼리 언어 - (5)  (0) 2025.02.18