[스프링 데이터 JPA] 나머지 기능들

윤경·2021년 11월 29일
0

JPA

목록 보기
21/22
post-thumbnail
post-custom-banner

사실 이 기능들을 실무에서 잘 쓰지 않으니까 그냥 편하게 듣기

[1] Specifications(명세)

스프링 데이터 JPA는 JPA Criteria를 확용해 이 개념을 사용할 수 있도록 지원함

이 기능도 강사님은 실무에서 쓰지 못하도록 금지시키고 있음(하루만 지나도 읽을 수가 없음 ㅜ)

술어(predicate)

  • 참 또는 거짓으로 평가
  • AND OR 같은 연산자로 조합해 다양한 검색조건을 쉽게 생성함(컴포지트 패턴으로)
    Ex. 검색 조건 하나하나
  • 스프링 데이터 JPA는 org.springframework.data.jpa.domain.Specification 클래스로 정의

명세 기능을 사용하려면 JpaSpecificationExecutor 인터페이스를 상속받으면 된다.

Specification을 파라미터로 받아 검색 조건으로 사용한다.

  • Specification을 구현하면 명세들을 조립할 수 있다.
    (where(), and(), or(), not() 제공)

  • findAll을 보면 (예제 상에서)회원 이름 명세(username)과 팀 이름 명세(teamName)를 and로 조합해 검색 조건으로 사용한다.

  • 명세를 정의하려면 Specification 인터페이스를 구현

  • 명세를 정의할 때는 toPredicate(...) 메소드만 구현하면 되는데 JPA Criteria의 Root, CriteriaQuery, CriteriaBuilder 클래스를 파라미터 제공

  • (예제에서는 편의상 람다를 사용)

⚠️ 실무에서는 JPA Criteria를 거의 쓰지 않는다! 대신 QueryDSL을 사용한다!


[2] Query By Example

이전과 같이 쿼리를 하는데 Example에 의해 쿼리를 하겠다(?)

테스트 결과 (그 옆에 age가 함께 설정되는 것은 ExampleMatcher를 생성해 무시시키면 됨)

  • Probe란 필드에 데이터가 있는 실제 도메인 객체
  • ExampleMatcher는 특정 필드를 일치시키는 상세한 정보를 제공하며 재사용이 가능
  • Example: ProbeExampleMatcher로 구성되었으며 쿼리를 생성하는데 사용

장점

  • 동적 쿼리를 편리하게 처리
  • 도메인 객체를 그대로 사용
  • (이게 좋은데) 데이터 저장소를 RDB에서 NOSQL로 변경해도 코드 변경이 없게 추상화 되어있음 (DB에 구애받지 않음)
  • 스프링 데이터 JPA(JpaRepository) 인터페이스에 이미 포함 (repository를 받으면 그냥 쓸 수 있음)

단점

⚠️ 강사님은 조인이 안되면 실무에 도입하지 않는 편

  • 조인은 가능하지만 내부조인(INNER JOIN)만 가능하고 외부조인(LEFT JOIN)은 안됨
  • 다음과 같은 중첩 제약 조건 안됨
    - firstname = ?0 or (firstname = ?1 and lastname = ?2)
  • 매칭 조건이 매우 단순
    - 문자는 starts/contains/ends/regex
    - 다른 속성은 정확한 매칭(=)만 지원 (equal 정도만 지원한다고 보면 됨)

즉, 실무에서 사용하기엔 매칭 조건이 너무 단순하고 LEFT 조인이 안된다.

그냥 실무에서는 QueryDSL을 사용하자!
자꾸 똑같은 결론이 나는 강사님,,,


[3] Projections

앞 기능들은 자꾸 도움이 안된다고 했는데 이건 그래도 좀 쓸모가 있어서 알아두면 좋음^^,,

엔티티 대신 DTO를 편리하게 조회할 때 사용한다.
예를 들어 전체 엔티티가 아니라 회원 이름만!! 조회하고 싶다면,, 🤷🏻‍♀️

회원 이름만 조회하고 싶다면 인터페이스에 getUsername()만 만들어놓으면 실제 구현체는 스프링 데이터 JPA가 만들어줌
조회할 엔티티의 필드를 getter 형식으로 지정하면 해당 필드만 선택해 조회(Projection)

디버깅 ➡️ 인터페이스에 추상화시킨 username만 정확하게 가져올 수 있게 되었음.

인터페이스 기반 Open Projections

스프링 SpEL 문법 지원

⚠️ 단, SpEL 문법을 사용하면, DB에서 엔티티 필드를 다 조회해온 다음 계산한다. 따라서 JPQL SELECT 절 최적화가 안된다.

클래스 기반 Projection

인터페이스가 아닌 구체적인 DTO 형식도 가능하다.
생성자의 파라미터 이름으로 매칭된다.

➡️ UsernameOnlyDto로 바꿔 돌린 결과

동적 Projections

Generic type을 주면 동적으로 프로젝션 데이터를 변경할 수 있다.

주의

  • 프로젝션 대상이 root 엔티티면, JPQL SELECT절 최적화 가능
  • 프로젝션 대상이 root가 아니라면
    - LEFT OUTER JOIN 처리
    - 모든 필드를 SELECT해서 엔티티로 조회한 다음 계산

📌 즉, 정리하자면

  • 프로젝션 대상이 root 엔티티면 유용
  • 프로젝션 대상이 root 엔티티를 넘어가면 JPQL SELECT 최적화가 안됨!!
  • 실무의 복잡한 쿼리를 해결하기엔 한계
  • 실무에서는 단순할 때만 사용, 조금만 복잡해지면 QueryDSL을 사용
    어,,?

[4] 네이티브 쿼리

제약이 너무 많기 때문에 가급적 네이티브 쿼리는 사용하지 않는 것이 가장 좋다‼️ (정말 어쩔 수 없을 때만 사용하자,,)
최근에 나온 궁극의 방법 → 스프링 데이터 Projections 사용

스프링 데이터 JPA 기반 네이티브 쿼리

  • 페이징 지원
  • 반환 타입(Object[], Tuple, DTO(스프링 데이터 인터페이스 Projections 지원)
  • 제약
    - Sort 파라미터를 통한 정렬이 정상 동작하지 않을 수 있음(믿지말고 직접 처리하자)
    - JPQL처럼 애플리케이션 로딩 시점에 문법 확인 불가
    - 동적 쿼리 불가

JPQL은 위치 기반 파라미터를 1부터 시작하지만 네이티브 SQL은 0부터 시작

네이티브 SQL을 엔티티가 아닌 DTO로 변환하려면

  • DTO 대신 JPA TUPLE 조회
  • DTO 대신 MAP 조회
  • @SqlResultSetMapping → 복잡
  • Hibernate ResultTransformer를 사용해야 함 → 복잡
  • 네이티브 SQL을 DTO로 조회할 때는 JdbcTemplate 또는 myBatis를 권장한다.

결과


profile
개발 바보 이사 중
post-custom-banner

0개의 댓글