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 활용
- 스프링 데이터 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 에러 발생
- repositoryBaseClass 로 커스터마이징 리포지토리를 설정할 경우, QuerydslPredicateExecutor 의 구현체가 없어짐
> 기존에는 QuerydslJpaRepository가 구현함
> QuerydslJpaRepository가 depreciated 되면서 , SimpleJpaRepository를 extends 해도 구동됨!! (강의에서는 안됨 )
>> 추가강의
> 1. 커스터마이징 레포지토리 인터페이스에 QuerydslPredicateExecutor 를 extends 함
> 2. 커스터마이징 레포지토리 구현체에 extends QuerydslRepositorySupport를 상속받으면 됨
'Spring' 카테고리의 다른 글
[Spring] 스프링 데이터 JPA - 4 (0) | 2021.07.26 |
---|---|
[Spring] 스프링 데이터 JPA - 3 (0) | 2021.07.25 |
[Spring] 스프링 데이터 JPA - 1 (0) | 2021.07.22 |
[Spring] 스프링 부트 업데이트 - 4 (0) | 2021.07.22 |
[Spring] 스프링 부트 업데이트 - 3 (0) | 2021.07.21 |