본문 바로가기
Book

자바 ORM 표준 JPA 프로그래밍 - JPA 정리하기 (10-2) 객체 지향 쿼리 언어

by devLog by Ronnie's 2022. 10. 30.

JPQL / Criteria / QueryDSL / 네이티브 SQL / JDBC 직접 사용 / SQL 매퍼에 대한 개념을 정리한다. 10강의 나머지 2편을 정리한다.

 

자바 ORM 표준 JPA 프로그래밍 - JPA 정리하기 (10-2) 객체 지향 쿼리 언어

 

자바 ORM 표준 JPA 프로그래밍 - JPA 정리하기 (10-2) 객체 지향 쿼리 언어


10.3 Criteria

  • JPQL을 자바 코드로 작성하도록 도와주는 빌뎌 클래스 API
  • 문자가 아닌 코드로 작성하므로 문법 오류를 컴파일 단계에서 잡을 수 있고 문자 기반의 JPQL보다 동적 쿼리를 안전하게 생성 가능 하다는 장점
  • 하지만 코드가 복잡하고 장황해서 직관적 이해가 떨어지는 단점

10.3.1 Criteria 기초

  • 검색 조건부터 정렬까지 Criteria 빌더를 사용해서 코드를 완성함
  • 쿼리 루트를 만들고 쿼리 루트는 조회의 시작점

10.3.2 Criteria 쿼리 생성

  • CriteriaBuilder.createQuery() 메서드로 Criteria 쿼리를 생성

10.3.3. 조회

  • 조회 대상 한건 -> select
  • 조회 대상 여러건 -> multiselect
  • 중복 제거 -> select distinct (select 다음에 사용)
  • NEW, construct() -> Criteria에서는 코드를 직접 다루므로 cq.select(cb.construct(MemberDTO.class, m.get(“”username))) 에서 MemberDTO.class처럼 간략히 사용 가능 (JPQL에서는 패키지명을 다 적어줘야함)
  • 튜플 : Criteria는 Map과 비슷한 튜플이라는 특별한 반환 객체를 제공함

10.3.4 집합

  • GROUP BY, HAVING 사용 가능

10.3.5 정렬

  • orderBy() 내의 desc(), asc() 제공

10.3.6 조인

  • 조인은 join() 메서드와 JoinType 클래스를 사용함
  • m.join("team" , JoinType.INNER)

10.3.7 서브 쿼리

  • 기본적인 서브 쿼리를 제공함
  • 메인 쿼리와 서브 쿼리 간에 사러 관련이 있는 상호 관련 서브 쿼리도 제공하는데 이때 서브 쿼리에서 메인 쿼리의 정보를 사용하려면 메인 쿼리에서 사용한 별칭을 얻어야 한다.

10.3.8 IN 식

  • in() 제공

10.3.9 CASE 식

  • CASE식에는 selectCase() 메서드와 when(), otherwise() 사용

10.3.10 파라미터 정의

  • parameter(타입, 파라미터 이름)으로 정의 가능
  • 하이버네이트는 Criteria에서 파라미터를 정의하지 않고 직접 값을 입력해도 실제 SQL에서는 PreparedStatement에서 파라미터 바인딩을 사용함

10.3.11 네이티브 함수 호출

  • function() 메서드를 통해 사용

10.3.12 동적 쿼리

  • 다양한 검색 조건에 따라 실행 시점에 쿼리를 생성하는 것을 동적 쿼리라 함
  • Criteria를 이용한 동적 쿼리는 최소한 공백이나 where, and의 위치로 인해 에러가 발생 하지 않음.
  • 하지만 이러한 장점을 불구하고 Criteria의 장황하고 복잡함으로 인해 코드가 읽기 힘들다는 단점은 남아있다.

10.3.14 Criteria 메타 모델 API

  • Criteria는 코드 기반이므로 컴파일 시점에 오류를 발견할 수 있음
  • 하지만 m.get(“age”)에서 age문자를 ageeg 잘못 적으면 컴파일 시점에 에러를 발견하지 못함 -> 즉 완전한 코드 기반이라 할 수 없음
  • 이런 부분까지 코드로 작성하려면 메타 모델 API를 사용하면 됨
  • 해당 모델을 사용하기 위해 먼저 메타 모델 클래스를 만들어야 함
  • 코드 생성기 설정
    • 코드 생성기는 보통 메이븐이나 엔트, 그래들 같은 빌드 도구를 사용해서 실행한다.

10.4 QueryDSL

  • 쿼리를 문자가 아닌 코드로 작성해도 쉽고 간결하며 그 모양도 쿼리와 비슷하게 개발할 수 있는 프로젝트가 바로 QueryDSL
  • 처음에는 HQL을 코드로 작성할 수 있도록 해주는 프로젝트로 시작해서 지금은 JPA, JDO, JDBC, MongDB ..등 을 다양하게 지원

10.4.1 QueryDSL 설정

  • 필요 라이브러리
    • querydsl-jpa: QueryDSL JPA 라이브러리
    • querydsl-apt: 쿼리 타입 (Q)을 생성할 때 필요한 라이브러리
  • 환경 설정
    • 엔티티를 기반으로 쿼리 타입이라는 쿼리용 클래스를 생성해야함

10.4.3 검색 조건 쿼리

  • where 절에는 and 나 or을 사용할 수 있음
  • 코드로 작성되어 있으므로 ide가 제공하는 코드 자동 완성 기능의 도움을 받을 수 있음

10.4.4 결과 조회

  • 쿼리 작성이 끝나고 결과 조회 메소드를 호출하면 실제 디비를 조회
  • uniqueResult() : 조회 결과가 한 건일때 사용, 없으면 Null 반환하고 하나 이상이면 NonUniqueResultException 발생
  • singleResult() : uniqueResult()와 같지만 결과가 하나 이상이면 처음 데이터 반환
  • list() : 결과 하나 이상일때 사용, 없다면 빈 컬렉션 반환

10.4.5 페이징과 정렬

  • 정렬은 orderBy() 사용하며 쿼리 타입이 제공하는 asc(), desc() 사용
  • 페이징은 offset, limit을 적절히 사용

10.4.6 그룹

  • groupBy를 사용하고 그룹화된 결과를 제한하려면 having 사용

10.4.7 조인

  • 조인은 innerJoin(), leftJoin(), rightJoin, fullJoin 사용
  • 추가로 JPQL의 on과 성능 최적화를 위한 fetch조인도 사용 가능
  • 조인의 기본 문법은 첫번째 파라미터에 조인 대상을 지정하고 두번째 파라미터에 별칭으로 사용할 쿼리 타입 지정하면 됨 (ex : leftJoin(order.orderltems, orderltem))

10.4.8 서브 쿼리

  • 서브쿼리의 결과가 하나면 unique(), 여러 건이면 list() 사용

10.4.9 프로젝션과 결과 반환

  • select절에 조회 대상을 지정하는 것을 프로젝션이라 함
  • 쿼리 결과를 엔티티가 아닌 특정 객체로 받고 싶으면 빈 생성 기능을 사용
  • QueryDSL은 객체 생성하는 다양한 방법 3가지
    • 프로퍼티 접근
    • 필드 직접 접근
    • 생성자 사용

10.4.10 수정, 삭제 배치 쿼리

  • 수정, 삭제 같은 배치 쿼리 지원함
  • JPQL 배치 쿼리와 같이 영속성 컨텍스트를 무시하고 디비를 직접 쿼리한다는 점에 유의
  • 삭제 배치 쿼리는 com.mysema.query.jpa.impl.JPADeleteClause 를 사용

10.4.11 동적 쿼리

  • BooleanBuilder 사용

10.4.12 메소드 위임

  • 메소드 위임 기능을 사용하면 쿼리 타입에 검색 조건을 직접 정의할 수 있음
  • 메소드 위임 기능을 사용하려면 정적 메소드로 만들고 @QueryDelegate를 통해 이 기능을 적용할 엔티티를 지정함.

 

댓글