-
Spring Data JpaJPA/JPA 2023. 2. 22. 08:57
Spring Data JPA
- 지루하게 반복되는 CRUD 문제를 세련된 방법으로 해결
- 개발자는 인터페이스만 작성한다
- 스프링 데이터 JPA가 구현 객체를 동적으로 생성해서 주입
- 스프링 데이터 JPA 적용 전
public class ItemRepository { public void save(Item item) {...} public Item one(Long id) {...} public List<Item> findAll() {...} } - public class MemberRepository {
public void save(Member member) {...}
public Member findOne(Long id) {...}
public List<Member> findAll() {...}
public Member findByUsername(String username) {...}
} - 스프링 데이터 JPA 적용 후
- 스프링 데이터 JPA에서는 JpaRepository 인터페이스를 제공한다.
- 우리가 상상할 수 있는 모든 API를 모두 처리한다.
- 인터페이스가 인터페이스를 상속받을 때는 extends를 사용한다.
public interface ItemRepository extends JpaRepository<Item, Long> { // 비어있음 } - public interface MemberRepository extends JpaRepository<Member, Long> {
Member findByUsername(String username);
}
스프링 데이터 JPA 적용 후 클래스 다이어그램
- JpaRepository에서 엄청 많은 기능을 제공한다. 인터페이스 상속 받아서 사용하면 된다.
- 기본적으로 CRUD를 구현하지 않아도 된다. 인터페이스 호출해서 쓸 수 있다.
- 스프링 로딩 시점에 MemberRepository와 ItemRepository의 구현체를 만든다.

공통 인터페이스 기능
- JpaRepository 인터페이스: 공통 CRUD 제공
- 제네릭은 <엔티티, 식별자>로 설정한다.
- 스프링에 스프링 데이터 프로젝트와 스프링 데이터 JPA프로젝트가 따로 존재한다.
- 스프링 데이터 프로젝트에 공통적인 기능을 가지고 있고, JPA 특화된 기능을 스프링 데이터 JPA 프로젝트에서 가지고 있다.
-

쿼리 메서드 기능
- 위에서 스프링 데이터 JPA 적용 전의 코드를 보면 findByUsername() 메서드가 있다.
- JpaRepository만으로 이걸 어떻게 처리하나?
- 이를 위해 쿼리 메서드라는 엄청난 기능이 존재한다.
- 메서드 이름으로 쿼리를 생성한다. @Query 어노테이션으로 쿼리를 직접 정의할 수 있다.
메서드 이름으로 쿼리 생성
- 메서드 이름만으로 JPQL 쿼리를 생성한다.
- 선언된 메서드에 대해서는 애플리케이션 로딩 시점에 쿼리를 다 만들어 버린다.
- 그래서 에러를 사전에 잡을 수 있다.
List<Member> member = memberRepository.findByName("hello")// 실행된 SQL SELECT * FROM MEMBER M WHERE M.NAME = "hello" - public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByName(String username);
}
이름으로 검색 + 정렬
- 자주 쓰는 기능 정렬을 위해 Sort를 넣어줄 수 있다. 스프링 데이터에서 만들어 놨다.
// 실행된 SQL SELECT * FROM MEMBER M WHERE M.NAME = "hello" ORDER BY AGE DESC - public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByName(String username, Sort sort);
}
이름으로 검색 + 정렬 + 페이징
- 추가로 페이징을 위한 기능도 만들어 놨다.
- 실제로 사용할땐 꼭 DTO로 변환해서 뿌리자.
- Page객체의 content에 데이터가 나오고,
- Pageable, sort, first, empty등의 정보를 얻을 수 있다.
// 예를 들어 이런식으로 사용할 수 있다. @GetMapping("/hello") public Page<Member> member() { PageRequest request = PageRequest.of(1, 10); return repository.findByName("hello1", request); } - public interface MemberRepository extends JpaRepository<Member, Long> {
Page<Member> findByName(String username, Pageable pageable);
} - 사용 예시
- Pageable page = new PageRequest(1, 20, new Sort...);
Page<Member> result = memberRepository.findByName("hello", page);
//전체 수
int total = result.getTotalElements();
//데이터
List<Member> members = result.getContent();
전체 페이지 수, 다음 페이지 및 페이징을 위한 API 다 구현되어 있음 - 실행된 SQL 2가지
- 데이터 조회
- SELECT *
FROM
( SELECT ROW_.*, ROWNUM ROWNUM_
FROM
( SELECT M.*
FROM MEMBER M WHERE M.NAME = 'hello'
OEDER BY M.NAME
) ROW_
WHERE ROWNUM <= ?
)
WHERE ROWNUM_>? - 전체 수 조회
- SELECT COUNT(1) FROM MEMBER M WEHRE M.NAME = 'hello'
@Query, JPQL 정의
- @Query 어노테이션을 사용해서 직접 JPQL을 지정할 수 있다.
- 마찬가지로 Named 쿼리도 애플리케이션 로딩 시점에 파싱을 하므로, 이로 인해 런타임 에러를 내지 않을 수 있다.
- public interface MemberRepository extends JpaRepository<Member, Long> {
@Query("select m from Member m where m.username = ?1")
Member findByUsername(String username, Pageable pageable);
}
Web 페이징과 정렬 기능
- 컨트롤러에서 페이징 처리 객체를 바로 인젝션 받을 수 있다
- page: 현재 페이지
- size: 한 페이지에 노출할 데이터 건수
- sort: 정렬 조건
- /members?page=0&size=20&sort=name,desc
- @RequestMapping(value = "/members", method = RequestMethod.GET)
String list(Pageable pageable, Model mobel) {}
출처:
https://ict-nroo.tistory.com/117
- 자바 ORM 표준 JPA 프로그래밍
- 저자 직강 - https://www.youtube.com/watch?v=WfrSN9Z7MiA&list=PL9mhQYIlKEhfpMVndI23RwWTL9-VL-B7U
'JPA > JPA' 카테고리의 다른 글
JPA 필드와 컬럼 매핑 (0) 2023.02.22 JPA기초(매핑) (0) 2023.02.22 ORM과 JPA 소개(2) (0) 2023.02.22 ORM과 JPA소개(1) SQL 중심 개발의 문제점 (0) 2023.02.22