ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Data Jpa
    JPA/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

    '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

    댓글

Designed by Tistory.