Spring Data JPA 정리

GyuHyeong·2021년 5월 22일
0

JPA시리즈

목록 보기
2/2

Spring Data JPA ?

JPA의 구현체인 Hibernate를 이용하여 Spring Framework에서 보다 편리하게 JPA를 사용하도록 돕는 프레임워크

Spring Data JPA를 이용한다면 그냥 JPA를 이용하는 것보다 더 높은 생산성을 갖게됩니다.
그 이유는

  1. Repository에 선언한 Method명으로 내가 원하는 쿼리를 DB로 전송하도록 구성할 수 있음
  2. 페이징, 정렬에 관련된 기능을 편하게 사용할 수 있음
  3. Spring Boot를 사용한다면 별다른 설정 없이 의존성만 추가하면 인터페이스의 상속만으로 JPA사용가능
  4. Auditing, Collection객체 fetch시 Paging기능 등

크게 이렇게 구분 할 수 있습니다. 물론 더 많은 장점이 있지만 개인적으로는 이 정도의 장점만으로도 JPA를 사용할때 Spring Data JPA를 선택하는데 충분하리라 생각됩니다.


메소드명으로 쿼리 생성하기

Spring Data JPA를 처음 사용해보면 정말 신기하다고 생각 드는 기능중 하나입니다.
이미 Spring Data JPA에는 findById(), findAll(), exsistById(), deleteById()등의 메소드가 구현되어있고, 해당 메소드를 사용하여 해당 인자값을 할당해주면 알아서 해당 쿼리가 날아갑니다.
만약 Id값으로 조회하는게 아닌, Name값으로 조회하고싶다면 어떻게 해야할까요?

이 때는 JpaRepository 인터페이스를 상속받은 인터페이스 내부에 findByName(String name) 메소드를 정의하고, 리턴타입을 해당 객체로 정의한다면 인자로 준 name값을 토대로 select쿼리가 전송되어 해당 데이터가 바인딩된 객체가 반환됩니다.

처음 사용해보면 진짜 신기해서 이것저것 막 건드려보게되는 흥미로운 기능입니다.
메소드명으로 쿼리만드는게 어디까지 지원되는지는 아래 공식문서를 보시면 됩니다.
https://docs.spring.io/spring-data/data-jpa/docs/2.5.x/reference/html/#repository-query-keywords
현재 최신버전이 2.5.x버전이라 해당 문서버전도 2.5.x버전 인 점 숙지하셔서 보시면 될것같습니다.
이 것만으로도 데이터의 단순 CRUD동작은 커버되니 꽤 편리합니다.


페이징, 정렬에 관련된 기능

기존 DB의 페이징을 해야할 경우 페이징과 관련된 SQL을 별도로 작성하고 해당 페이지에 대한 정보를 파라미터로 받은다음 이 정보들을 다시 리스트하거나 전체 엔티티수가 몇개인지 카운트쿼리를 작성해서 또 보내고 이 값을 이용한다던지 등의 페이징 기능 하나를 위해 수반되는 여러 부수적인 일들에 대해 간단한 방법으로 이를 해결해주는 기능이 있습니다.

바로 Pageable과 Page, Slice객체인데요.
우선 Pageable의 경우 URL에 QueryString으로 size, page, data&sort 정보를 파라미터로 포함해 요청하게되면
이를 스프링에서 자동으로 Pageable객체로 바인딩해 컨트롤러의 메소드에 주입해줍니다.
이를 이용해 Repository의 페이징 할 메소드의 인자에 그냥 그 Pageable 객체를 주기만하면 됩니다.

여기서 만약에 Page객체로 받게된다면 해당하는 데이터의 전체 갯수도 카운트해오는 쿼리가 하나 더 발생해서 조회해오게되고, Slice객체로 받는다면 페이징사이즈 + 1만큼의 데이터 개수를 조회해서 페이징사이즈보다 더 많은 데이터 수가 조회되면 다음 페이지가 있는것으로 간주하게됩니다.
조회한 데이터는 Page, Slice클래스에 선언되어있는 .getContent()메소드를 이용하게 된다면 리스트타입으로 반환받을 수 있습니다.

정렬의 경우는 Pageable객체에 Sort객체를 별도로 만들어 세팅해주거나, URL의 data&sort 파라미터에 데이터명, 순서를 정해준 뒤 Repository의 인자로 보내주면 정렬이 된 상태로 데이터를 반환받습니다.
(이 방법은 정렬이 조금만 복잡해져도 쓰기 어렵기 때문에 별도로 정렬을 해주시는걸 추천드립니다. 아니면 QueryDsl쓰세요)


Auditing, Collection fetch Paging

Auditing
특정 클래스에서 공통적으로 저장하거나 수정해야할 필요가 있는 경우가 있습니다.
예를 들자면 회원가입시 가입일과 회원정보 수정시간 같은 데이터를 저장해둬야 할 때등이죠
Spring Data JPA에선 해당하는 필드들을 가진 클래스를 하나 새로 만들어서 거기다 공통수행할 메소드를 작성해 두고
그 메소드에 @Prepersist나 @Preupdate등의 어노테이션을 선언해둔 뒤 공통적용할 클래스에 이 클래스를 상속받도록 구현하면 됩니다. 그러면 알아서 어노테이션에 표시된 동작 시점에서 메소드가 동작하게됩니다.
이는 공통기능때문에 발생하는 코드 중복을 줄여 유지/보수성을 높이는데 중요합니다.

Collection fetch paging
원래 JPA에선 Collection fetch join시 paging을 하게 되면 예외가 발생합니다.
하지만 하이버네이트에선 경고로그를 띄우고 데이터베이스에서 관련된 데이터를 전부 가져온뒤 Application단에서 페이징을 하게됩니다.
이 경우 데이터가 상당히 많은 경우에는 OutofMemory예외가 발생할 우려가 있고, 서버의 부하가 엄청나게 증가하게 되고, 또한 n+1의 문제에서 벗어날 수 없습니다.
이러한 이유때문에 일반적으로 Collection fetch시엔 paging을 하지않는것이 권장되고, N:1관계에서의 페이징을 하도록 권장하고있습니다. 하지만, 개발을 하다보면 1:N 관계에서 fetch와 페이징을 써야할 때가 있습니다.
이럴때 Spring Data JPA가 빛을 발하는데, 바로 @batch_fetch_size입니다.
이는 해당 애노테이션에서 정의한 갯수를 한계점으로 collection객체의 id값이 select query 마지막에 in(?,?,?~)식으로 붙어서 조회되게 됩니다. (정말 엄청난 기능입니다.)
이 기능을 이용하게 되면 Collection fetch시 발생하는 n+1문제와 서버단의 과부하 문제를 단번에 해결할 수 있는 기능이라 정말 중요합니다.
이 기능을 공통적으로 사용하려면 application.yml이나 application.properties에
spring.jpa.properties.default_batch_fetch_size 값을 지정해주시면 되고, 값은 보통 100~1000 정도를 권장합니다.


마치며

사실 더 많은 기능들이 있지만 간략하게 JPA를 쓸때 Spring Data JPA를 쓰면 어떤점이 좋은지에 대해 크게 와닿을만한 것들 위주로 정리했습니다.

음.. 하지만 Spring Data JPA를 사용하더라도 좀 복잡한 쿼리같은 경우 JPQL이나 Native SQL을 사용할 수 밖에 없는데요.
이러한 문제점을 해결하기위해 한줄기 빛처럼 등장한 오픈소스 라이브러리가 있습니다.
바로 QueryDsl 인데요. 이에 대해서도 정리해보도록 하겠습니다.

혹시 틀린 내용이 있거나, 더 궁금하신 사항이 있으시다면 댓글 달아주세요.

해당글은 인프런의 김영한님이 제작하신 Spring Data JPA강좌를 참고하여 작성되었습니다.

profile
잘하고 싶은 주니어 백엔드 개발자 입니다.

0개의 댓글