본문으로 바로가기

[Spring] 스프링 데이터 JPA - 2

category Spring 2021. 7. 23. 17:29

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-jpa

 

스프링 데이터 JPA - 인프런 | 강의

JPA(Java Persistence API)를 보다 쉽게 사용할 수 있도록 여러 기능을 제공하는 스프링 데이터 JPA에 대해 학습합니다., 스프링 데이터 JPA JPA(Java Persistence API)를 보다 쉽게 사용할 수 있도록 여러 기능을

www.inflearn.com

 

ㅇ 스프링 데이터 JPA 활용

- 스프링 데이터 Common : 여러 저장소 지원 프로젝트의 공통 기능 제공

 > 스프링 데이터 JPA : 스프링 데이터 Common이 제공하는 기능에 JPA 관련 기능 추가

 

ㅁ 스프링 데이터 Common

* 리포지토리

- JpaRespository를 따라가보면 여러가지를 상속 받음

 > crudrepository 및 JpaRepository 가 실제 기능 구현

 > @NoRepositoryBean 이 달려있어서, bean으로 등록되지는 않음

- Long은 long의 reference 타입

- 테스트를 작성했는데, Rollback할 쿼리이기 때문에, inser를 안함

 > @Rollback(false) 를 달아줌

- repository.findAll 을 Page<>로 받아서 처리하는것

 > 검색 조건과 정렬을 사용하여 확인할 수 있음

 

* 인터페이스 정의

- 기존에는 SpringData JPA, Commons 가 제공하는 JpaRespository를 상속받아 사용

- 인터페이스로 @RepositoryDefinition 만 만들어도, 스프링 데이터 JPA가 우리가 정의한 메소드의 구현체를 제공해준다.

 > 그래서 메소드만 정의해도 사용 가능

- 아래와 같이 아예 Repository 인터페이스를 생성하여 쓰고싶은 메소드만 정의 가능

import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository;

import java.io.Serializable;
import java.util.List;

@NoRepositoryBean
public interface MyRepository<T,Id extends Serializable> extends Repository<T, Id> {

    <E extends T> E save(E entity);

    List<T> findAll();

    Long count();
}

 

* Null 처리하기

- Optional (자바 8 부터 지원 ) 사용하기

 > Optional은 isEmpty()로 확인

 > 비어있으면 Null으로 리턴 받음

 > Optional 은 orElse, orElseThrow 등으로 처리 가능

- 단일값으로 받아오면 Optional로 처리하는게 좋음

- Repository에서 Collections으로 리턴할 경우, 무조건 null이 아님

 > 비어있는걸로 체크해야함

- @NonNull, @Nullable 활용 (스프링 프레임워크 5.0 부터 지원 )

 > 패키지단에 쓸수 있는, @NonNullApi 가 있다. (잘 안쓸듯.. )

 

 * 쿼리 만들기 

- 인터페이스에 적은 메소드의 이름을 분석해서 Spring JPA가 쿼리를 만들어준다. (CREATE)

-  미리 정해둔 쿼리 찾아 사용하기 (USE_DECLARED_QUERY)

 > @Query 사용 (기본은 JPQL, nativeQuery= true로 하고 SQL 사용)

-  미리 정의한 쿼리 찾아보고 없으면 만들기 (CREATE_IF_NOT_FOUND)

 > queryLookupStrategy로 설정

- 쿼리 만드는 방법

 

 >  pageable에 sort할 수 있음 (Sorting이 포함된 개념 )

 > Sort sort를 인자로 넣어서 Sorting 할 수도 있음

- like라는 키워드로 멤버변수를 만드니 문제가 생김 (likeCount로 변경)

- Page, Stream 으로 받아 처리하기

- @async와 같이 쓰고 싶으면 @EnableAsync 를 Application에 써야함

- Future 로 리턴 받으면 Non-blocking 메소드가 됨

 => 하지만 이후 future.get() 을 하는 순간, blokcing이 됨 ( 값이 올때까지 기다림 )

 > 문제 발생

 > ListenableFuture로 해결

  > 콜백 함수 작성 가능

- DB 와의 통신에서 성능 개선을 위해 비동기 쿼리를 쓰는건 추천하지 않음

 > 비동기 쿼리로 메인쓰레드의 활동을 더 하게 할 수 있으나, 실제 쿼리가 실행되는건 DB문제 여서 

  개선이 어려움 (DB 병목현상을 개선)

 > WebFlux를 쓰는게 더 좋음

 

* 커스텀 리포지토리 만들기

- interface로 리포지토리 생성

 > 이후 구현체 ( 리포지토리+ Impl 로 생성 ) 로 기능 정의

 >> @EnableJpaRepositories(repositoryImplementationPostfix = "Default") 로 접미어 변경 가능

 > 다른데에서는 interface의 리포지토리를 가져와서 기능 사용

- 커스텀하게 구현한 구현체가 우선순위가 더 높음 ( JpaRepository 에서의 구현체는 맨 나중에 적용 )

- @Trasactional 의 경우, 스프링의 모든 테스트는 이 Transaction에 대해 롤백 으로 생각하게됨.

 > hibernate의 경우, 롤백에 대해 필요없는 쿼리를 날리지 않음

 > flush를 강제적으로 호출하면 sync를 함

   ( removed 상태나 이런거를 냅두지않고 sync하여 db에 반영함 )

- 모든 리포지토리에 공통적으로 추가하고 싶은 기능이 있거나 덮어쓰고 싶은 기본 기능을 구현할 수도 있다.

 > @EnableJpaRepositories(repositoryBaseClass = SimpleMyRepositor.class)

 

* 도메인 이벤트

- 스프링에는 이벤트 퍼블리싱, 리스닝이 내재되어 있음

 > 애플리케이션 컨텍스트가 이벤트 퍼블리셔임

   > bean팩토리 이상의 기능을 한다

 - 스프링 데이터 JPA가 entity에 쌓여있던 event가 save할때 모두 실행시킴

 > @DomainEvents : 이벤트를 모음

 > @AfterDomainEventPublication : 이벤트 실행시킴

 > extends AbstractAggregateRoot 로 entity에서 상속하면 위에것이 다 구현되어있음

  >> entity안에 this.registerEvent(new PostPublishedEvent(this)) 로 구현

 

* QueryDSL 연동

- Predicate 인터페이스 사용

 > typesafe 하고 여러개 predicate 연동 가능

- QuerydslPredicateExecutor 인터페이스

 > Optional<T> findOne(predicate)

 > List<T> | Page<T>| .. findAll

  >> Page 는 pageable 필요

- QueryDSL은 JPA 뿐만 아니라 여러가지 다른 API들도 지원

- 디펜던시 추가 , 플러그인 추가

 > error: Annotation processor 'com.mysema.query.apt.jpa.JPAAnnotationProcessor' not found 에러 발생

 > https://stackoverflow.com/questions/33741379/spring-data-jpa-specifications-and-querydsl 해결

 >  java.lang.UnsupportedOperationException 에러 발생

 > https://blog.leocat.kr/notes/2020/11/08/querydsl-version-mismatch-with-spring-boot-dependency-management 해결

 - repositoryBaseClass 로 커스터마이징 리포지토리를 설정할 경우, QuerydslPredicateExecutor 의 구현체가 없어짐

 > 기존에는 QuerydslJpaRepository가 구현함

 > QuerydslJpaRepository가 depreciated 되면서 , SimpleJpaRepository를 extends 해도 구동됨!! (강의에서는 안됨 )

  >> 추가강의 

   > 1. 커스터마이징 레포지토리 인터페이스에 QuerydslPredicateExecutor 를 extends 함

    > 2. 커스터마이징 레포지토리 구현체에 extends QuerydslRepositorySupport를 상속받으면 됨