Spring | JPA Specification & Criteria

Wonhee 📘·2022년 5월 28일
0

Spring

목록 보기
3/6
post-thumbnail

JPA Specification?

UT를 통해 검색기능과 관련한 피드백을 받게되어 작업을 하는데
조건이 점점 추가가 될 수록 if문이 많아지고 유지보수가 힘들어지게되어 비효율적이라는것을 느끼게 되었습니다.

JPA Specification란 DB 쿼리의 조건을 간단히 spec으로 작성하여 날릴 수 있게 해줍니다. 해당 Specification을 사용하면 코드도 짧아지고 유지보수에 효율적이게 되어 적용 해보게 되었습니다.

Specification 사용법

Specification을 적용하기 위해서는 JpaSpecificationExecutor<T>를 추가로 상속받아야 합니다.

ex)

public interface RoomRepository extends JpaRepository<Room, Long>, JpaSpecificationExecutor<Room>{
   ... (생략)
}

사용할 쿼리를 Spec에 입력합니다.

public class RoomSpecification {

    public static Specification<Room> equalTag1(String tag1) {
        return new Specification<Room>() {
            @Override
            public Predicate toPredicate(Root<Room> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.equal(root.get("tag1"), tag1);
            }
        };
    }
    
    public static Specification<Room> equalTitle(String keyword) {
        return new Specification<Room>() {
            @Override
            public Predicate toPredicate(Root<Room> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.like(root.get("title"),"%" + keyword + "%");
            }
        };
    }
}

equal, like, notlike, and, or, between 등 쿼리문을 동일하게 사용할 수 있다.

Specification<Room> spec = (root, query, criteriaBuilder) -> null;

if (tag1 != null)
	spec = spec.and(RoomSpecification.equalTag1(tag1));
if (keyword != null)
	spec = spec.and(RoomSpecification.equalTitle(keyword));
return roomRepository.findAll(spec, pageable);

처음 Specification<Room> spec을 null로 초기화합니다.

그리고 Controller가 받아온 파라미터가 null이 아니면 RoomSpecification에서 작성한 Specification<Room>을 반환 값을 and() 메서드에 넣어줍니다.

📃 참고

스프링 강사님으로 유명한 김영한님이 말씀하시길 실무에서는 JpaSpecificationExcutor를 사용하는 것은 권장하지 않는다고 한다.

JpaSpecification 자체가 결국 JPA가 제공하는 Criteria로 이루어지는데, JPA의 Criteria는 조금만 복잡해져도 장황하며 직관적으로 이해하기가 정말 어려워 지기 때문이다.

Criteria란?

Criteria 쿼리는 JPQL을 자바 코드로 작성하도록 도와주는 빌더 클래스 API이다. Criteria를 사용하면 문자가 아닌 코드로 JPQL를 작성하므로 문법 오류를 컴파일 단계에서 잡을 수 있고 문자 기반의 JPQL보다 동적 쿼리를 안전하게 생성할 수 있다

JPA Criteria(JpaSpecificationExecutor 포함)에 비해 편리하고 실용적인 QueryDSL을 쓰는것을 추천합니다.

profile
오늘 걷지 않으면 내일은 뛰어야한다 🚶‍♂️ 🏃‍♀️

1개의 댓글

comment-user-thumbnail
2022년 11월 3일

오늘 걷지 않으면 내일은 뛰어야한다 🚶‍♂️ 🏃‍♀️
라는 말에 문법상 오류가 있어 남기고갑니다.

오늘 걷는다면 내일은 뛰어야한다.
가 아닐 까 싶습니당 ㅇㅅㅇ..

답글 달기