SPRING-JPA에서 데이터 검색을 위한 질의(Query)방식은 여러가지가 있으며
총 5가지 방식으로 요약이 됩니다.
- SQL(Native)
- Query Function
- JPQL
- Criteria Query
- Query DSL
함수쿼리/JPQL은 앞장에서 다루었으며
QueryDSL과 Criteria Query 두가지 방식 사용법을 알아보겠습니다.
Code Link : http://git.webnori.com/projects/WEBF/repos/spring_jpa/browse/src/test/java/com/example/demo/jpa/JpaDSL.java
QueryDSL
SPRING-JPA 에서 QueryDSL사용을 위한 단계
- Entity QDomain 메타 지원을 위한 pom.xml 수정
- 기존 Repository 인터페이스에서, QueryDslPredicateExecutor 추가 상속받음
- Builder 클래스를 통해 각종 검색옵션 조합하여 , 기존 쿼리메스드(findall()) 에 인자값으로 전달가능
Spring-Boot-Starter 에서 QueryDSL 사용을 위한 pom.xml 수정
pom.xml을 수정후, 에러표시가 있다면 JAVA_HOME/PATH 등이 JDK경로를 지정하고 있는지 체크후
Maven-Update Project를 수행합니다.
QueryDSL지원을 위한 Repository 정의
JPA에서 사용하던 Repository에서 QueryDslPredicateExecutor 만 추가로 상속받으면 사용준비가 끝납니다.
Table Entity정의 역시 기존과 동일합니다. 차이점이 있다면, pom.xml에서 QueryDSL지원을 위한 메타빌드를 설정했기때문에
JPA에서 정의한 Entity를 자동 탐색하여 인해 QueryDSL에서는 QAddress 라는 도메인 객체를 자동 생성합니다. ( target/generated-sources/querydsl )
즉 기존Address Entity접두사에 Q가 자동 붙게 되어 , QueryDSL과 관련된 기능을 수행할수 있게됩니다.
package com.example.demo.data; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QueryDslPredicateExecutor; public interface AddressRepoDSL extends JpaRepository<Address, Long>, QueryDslPredicateExecutor<Address>{ }
QueryDSL을 활용하여 쿼리빌드하기
@Autowired private AddressRepoDSL addressRepoDSL; public void jpa_queryDslTest() { QAddress userAddress = QAddress.address1; BooleanBuilder builder = new BooleanBuilder(); builder.and(userAddress.name.eq("민수1") ) .and(userAddress.address.like("%" + "서" +"%")); Iterable<Address> addressList = addressRepoDSL.findAll(builder); addressList.forEach( item -> { String itemString = String.format("%d%s %s %s %s %s",item.getId(),item.getName(), item.getPhoneNbr(), item.getSex(),item.getAddress(),item.getAge()); System.out.println(itemString); }); }
builder.and(userAddress.name.eq("민수1") ); builder.and(userAddress.address.like("%" + "서" +"%"));
QueryDSL 의 핵심이 되는 검색조건을 만드는 방법입니다. TypeSafe하게 검색 조건을
유연하게 복합할수가 있습니다. 이것은 복합적인 검색인자값이 null 혹은 Optional 등을 포함하였을때
중첩 if문등을 억제할수가 있습니다.
조건식이 복잡해질시.. 중첩 if문 처리가 더욱더 어려워지고 sql문은 typesafe하지 않기때문에
어떠한 케이스에서는 sql문 syntax 에러를 유발 하였습니다.
검색 SQL문을 생성할때, 검색조건이 없는경우(null) 다양한 SQL문을 CaseBy로 복합적으로 만들어야 했습니다.
- Select * from address where name='민수1'
- Select * from address
- Select * from address where name='민수1' and addres like '%서%'
프로그래밍 모델에서 검색의 null값은 일반적으로 해당 옵션으로는 검색하지마, 전체라는 의미가 될수도 있고
DB에서는 null은 존재하지 않음(=null)/값이없음(isnull) 이라는 특수한 두가지 의미를 지니게되기때문에
쿼리문을 통해 전체검색조건이란 특정 옵션을 지정할수가 없습니다.
QueryDSL에서는 단지 필요한 조건만 동적으로, 부분 추가가 가능하기때문에
검색 결합/제거 등이 용이하며 TypeSafe하기때문에 잘못된 SQL문을 만들어내지 않습니다. (빌드타임에 걸러짐)
기존에는 3가지종류의 SQL문을 사용해야한 동일한 검색 옵션을 수행하던것을
아래와같이 두줄로 표현이 가능합니다. null은 어플리케이션에서도 애매모호한 값이며
Java의 Optional을 이용하면 null처리의 애매모호성에 대해 조금더 유연하게 처리가능하며...
이것은 추후 Rest를 이용한 검색API에서 다루도록 하겠습니다.
if(name!=null) builder.and(userAddress.name.eq("민수1") ); if(address!=null) builder.and(userAddress.address.like("%" + "서" +"%"));