Spring/SpringDataJPA

Specifications(명세)

느리지만 꾸준하게 2022. 4. 19. 15:56
  • Specifications
  • Query By Example
  • Projections
  • 네이티브 쿼리

Specifications을 지원하는데 JPA Criteria를 활용해서 개념을 사용할 수 있도록 지원해준다.

=> 실무에서 잘 사용하지 않는다.

 

술어(predicate)

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

 

사용방법을 보고 간단하게 넘어가자.

// MemberRepository Interface

public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom, JpaSpecificationExecutor<Member> {

    List<Member> findByUsernameAndAgeGreaterThan(String username, int age);

 

아래와 같이 테스트 케이스를 작성해주고

@Test
public void specBasic() {
    // given
    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();

    // when
    memberRepository.findAll();
}

 

MemberSpec을 만든 후에

아래와 같이 코드 작성

// MemberSpec

package study.datajpa.repository;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
import study.datajpa.entity.Member;
import study.datajpa.entity.Team;

import javax.persistence.criteria.*;

public class MemberSpec {


    // teamName 검색조건으로 넣을 것이다.
    public static Specification<Member> teamName(final String teamName) {
        return (root, query, builder) -> {

            if (StringUtils.isEmpty(teamName)) {
                return null;
            }

            // JPA Criteria 문법 => JPQL 만듬
            Join<Member, Team> t = root.join("team", JoinType.INNER);// 회원과 조인
            return builder.equal(t.get("name"), teamName);
        };
    }

    public static Specification<Member> username(final String username) {
        return (Specification<Member>) (root, query, builder) ->
                builder.equal(root.get("username"), username);
    }
}

 

테스트 코드에 when절을 작성후에 실행시키면

@Test
public void specBasic() {
    // given
    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();

    // when

    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_.age as age2_1_,
        member0_.created_date as created_3_1_,
        member0_.tema_id as tema_id5_1_,
        member0_.username as username4_1_ 
    from
        member member0_ 
    inner join
        team team1_ 
            on member0_.tema_id=team1_.team_id 
    where
        member0_.username=? 
        and team1_.name=?
2022-04-19 15:50:34.661  INFO 71773 --- [           main] p6spy                                    : #1650351034661 | took 0ms | statement | connection 3| url jdbc:h2:tcp://localhost/~/datajpa
select member0_.member_id as member_i1_1_, member0_.age as age2_1_, member0_.created_date as created_3_1_, member0_.tema_id as tema_id5_1_, member0_.username as username4_1_ from member member0_ inner join team team1_ on member0_.tema_id=team1_.team_id where member0_.username=? and team1_.name=?
select member0_.member_id as member_i1_1_, member0_.age as age2_1_, member0_.created_date as created_3_1_, member0_.tema_id as tema_id5_1_, member0_.username as username4_1_ from member member0_ inner join team team1_ on member0_.tema_id=team1_.team_id where member0_.username='m1' and team1_.name='teamA';

 

  • 실무에서는 JPA Criteria를 거의 안쓴다! QueryDSL을 사용하자.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<출처 김영한: 실전! 스프링 데이터 JPA >

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

 

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

스프링 데이터 JPA는 기존의 한계를 넘어 마치 마법처럼 리포지토리에 구현 클래스 없이 인터페이스만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 모두 제공합니다.

www.inflearn.com

 

'Spring > SpringDataJPA' 카테고리의 다른 글

Projections  (0) 2022.04.19
Query By Example  (0) 2022.04.19
새로운 엔티티를 구별하는 방법  (0) 2022.04.18
스프링 데이터 JPA 구현체 분석  (0) 2022.04.18
Web 확장 - 도메인 클래스 컨버터 & 페이징과 정렬  (0) 2022.04.18