반응형
Spring Data JPA 게시글은 대부분 인프런의 김영한님의 강의인 '실전! 스프링 데이터 JPA' 기반으로 내용을 정리했습니다.
나머지 기능들
- Specifications(명세)
- Query By Example
- Projections
- 네이티브 쿼리
나머지 기능들은 복잡도가 높지만 실무에서 그닥 필요하지는 않은 기능들이다. 그래도 개 똥도 약에 쓰려면 없다고, 알고 있으면 좋을 기능들이므로 이런 게 있구나 정도만 파악하면 될 것 같다.
Specifications(명세)
스프링 데이터 JPA는 JPA Criteria를 활용해서 이 개념을 사용할 수 있도록 지원한다. Criteria 앞에서 자주 좀 본 기능 같다. 하지만 기억에 잘 안 남는 거 보니 그다지 중요한 애는 아닌 거 같다. 강의에서도 말하길 이 기능은 JPA 설계가 가장 잘못된 기능 중 하나라고 한다(개인 의견이겠지만). 그만큼 실무에서는 잘 사용하지 않는 기능이라고 한다. 이유는 코드를 해독하는데 있어서 어려움이 많아 쿼리가 조금이라도 복잡해지면 사용하기가 어렵다 한다.
술어(predicate)
- 참 또는 거짓으로 평가
- AND OR 같은 연산자로 조합해서 다양한 검색 조건을 쉽게 생성(컴포지트 패턴)
- ex) 검색 조건 하나하나
- 스프링 데이터 JPA는 org.springframework.data.jpa.domain.Specification 클래스로 정의한다.
명세 기능 사용 방법
JpaSpecificationExecutor 인터페이스 상속
// MemberRepository.interface
public interface MemberRepository extends JpaRepository<Member, Long>,
MemberRepositoryCustom, JpaSpecificationExecutor<Member>{
전에 만들어 두었던 MemberRepository.interface에 extends 구문 맨 뒤에 JpaSpecificationExecutor<타입>을 추가해주면 된다. JpaSpecificationExeutor<T> 안을 들여다보면 뭔가 익숙한 메서드에 매개변수로 Specification<T>을 받는 걸 볼 수 있다.
List<T> findAll(@Nullable Specification<T> spec);
- MemberSpec.class
public class MemberSpec {
public static Specification<Member> teamName(final String teamName) {
return (Specification<Member>) (root, query, criteriaBuilder) -> {
if(StringUtils.isEmpty(teamName)) {
return null;
}
Join<Member, Team> t = root.join("team", JoinType.INNER);// 회원과 조인
return criteriaBuilder.equal(t.get("name"), teamName);
};
}
public static Specification<Member> username(final String username) {
return (Specification<Member>) (root, query, criteriaBuilder) ->
criteriaBuilder.equal(root.get("username"), username);
}
}
- MemberRepositoryTest.class
@Test
public void specBasic() {
Team teamA = new Team("teamA");
em.persist(teamA);
Member m1 = new Member("m1", 0, teamA);
Member m2 = new Member("m2", 0, teamA);
em.persist(m1);
em.persist(m2);
em.flush();
em.clear();
Specification<Member> spec = MemberSpec.username("m1").and(MemberSpec.teamName("teamA"));
List<Member> result = memberRepository.findAll(spec);
Assertions.assertThat(result.size()).isEqualTo(1);
}
select
member0_.member_id as member_i1_1_,
member0_.create_by as create_b2_1_,
member0_.create_date as create_d3_1_,
member0_.last_modified_by as last_mod4_1_,
member0_.last_modified_date as last_mod5_1_,
member0_.age as age6_1_,
member0_.team_id as team_id8_1_,
member0_.username as username7_1_
from
member member0_
inner join
team team1_
on member0_.team_id=team1_.team_id
where
member0_.username=?
and team1_.name=?
- Specification을 구현하면 명세들을 조립할 수 있다. where(), and(), or(), not()을 제공한다.
- findAll()을 보면 회원 이름 명세(username)와 팀 이름 명세(teamName)를 and로 조합해서 검색 조건으로 사용한다.
Specification의 장점 중 하나는 동적 쿼리를 편리하게 자바로 이용할 수 있다는 점이다. Specification 기능 자체는 괜찮은데 한 가지 아쉬운 점이 JPA Criteria를 사용한다는 것이다. 그러니 코드 자체가 너무 복잡하다. 그래서 예제 코드를 보면 한 눈에 들어오지 않는 단점이 있다.
! 그래서 결론은! 실무에서는 사용하지 말자.
반응형