Criteria API란?

자바 ORM 표준 JPA 프로그래밍에서 JPQL(객체지향쿼리) Java Persistence Query Language 을 자바 코드로 작성할 수 있도록 도와주는 빌더 클래스 API를 의미합니다. JPQL 조회를 위한 문자열 빌드에 하나의 대안으로 Java 오브젝트를 갖는 조회 빌드 API 입니다. JPQL은 런타임 중에 잘못된것이 있는지 확인해볼 수 있습니다. 

Criteria API 장단점

장점

  • 빌더 클래스로 컴파일 단계에서 문법 오류를 확인해볼 수 있습니다.
  • 쿼리문을 문자열 그대로 작성 시 발생할 수 있는 휴먼 에러를 방지할 수 있습니다. 

단점

  • 코드가 복잡해지면 가독성이 떨어지게 됩니다. 
  • API 사용에 대한 러닝커브가 존재합니다. 

Criteria API 기본 쿼리

Criteria API는 javax.persistence.criteria 패키지에서 관리되는것을 확인해볼 수 있습니다. 

1. getCriteriaBuilder 함수를 이용해서 Criteria Query Builder를 생성합니다. 

2. 쿼리 정보를 담기 위해 createQuery함수를 이용해 CriteriaQuery 객체를 생성하게 됩니다. 

3. select 절에 from절을 적용시키기 위해서 from 함수를 이용해 User.class를 받게됩니다.

4. 등록된 query 객체에 정보를 이용해 자바 코드 기반의 query 객체를 생성하게 됩니다. 

CriteriaBuilder cb = em.getCriteriaBuilder(); //Criteria 쿼리 빌더 생성

CriteriaQuery<User> cq = cb.createQuery(User.class); //Criteria 생성

Root<User> user = cq.from(User.class); //from 절
cq.select(user); 

TypedQuery<User> query = em.createQuery(query); //select 절 생성

List<User> users = query.getResultList();

Criteria API 검색 조건

1. getCriteriaBuilder 함수를 이용해서 Criteria Query Builder를 생성합니다. 

2. 쿼리 정보를 담기 위해 createQuery함수를 이용해 CriteriaQuery 객체를 생성하게 됩니다. 

3. 유저엔티티 별칭 user를 사용해서 user.id = "회원id" 을 조회해오게 됩니다. 

4. 생성한 조건을 이용해 where 절에 넣고 쿼리를 생성합니다.

CriteriaBuilder cb = em.getCriteriaBuilder();

CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> user = cq.from(User.class);

Predicate userId = cb.equal(user.get("id"), "회원id"); //검색 조건

cq.select(user)
  .where(id)

List<User> resultList = user.createQuery(cq).getResultList();

Criteria 쿼리 생성

  • CriteriaBuilder 인터페이스 메소드 시그니처 참고
  • CriteriaBuilder에서 반환타입 생성할 때 쿼리 만들 수 있는 3가지 방법이 존재합니다. 
public interface CriteriaBuilder {

    /**
     *  Create a <code>CriteriaQuery</code> object.
     *  @return criteria query object
     */
    CriteriaQuery<Object> createQuery();

    /**
     *  Create a <code>CriteriaQuery</code> object with the specified result 
     *  type.
     *  @param resultClass  type of the query result
     *  @return criteria query object
     */
    <T> CriteriaQuery<T> createQuery(Class<T> resultClass);

    /**
     *  Create a <code>CriteriaQuery</code> object that returns a tuple of 
     *  objects as its result.
     *  @return criteria query object
     */
    CriteriaQuery<Tuple> createTupleQuery();
  • 엔티티의 타입으로 객체 반환
    •  <T> CriteriaQuery<T> createQuery(Class<T> resultClass);
CriteriaBuilder db = em.getCriteriaBuilder();

CriteriaQuery<User> cq = cb.createQuery(User.class);

List<User> resultList = em.createQuery(cq).getResultList();
  • Object로 반환
    • CriteriaQuery<Object> createQuery();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Object> cq = cb.createQuery(); //타입이 Object인 쿼리를 반환

List<Object> resultList = em.createQuery(cq).getResultList();
  • Tuple 반환
    • CriteriaQuery<Tuple> createTupleQuery();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery(); //Tuple을 반환
TypeQuery<Tuple> query = em.createQuery(cq);

Criteria 조회

  • 단건 조회
CriteriaBuiolder cb = em.getCriteriaBuilder();

CriteriaQuery<User> cq = cb.createQuery(User.class);

Root<User> user = cq.from(User.class);

cq.select(user);
  • 다건 조회
CriteriaBuiolder cb = em.getCriteriaBuilder();

CriteriaQuery<User> cq = cb.createQuery(User.class);

Root<User> user = cq.from(User.class);

//JPQL
cq.multiselect(user.get("id"), user.get("imgaeUrl"));

//cb.array
cq.select(cb.array(user.get("id"), user.get("imgaeUrl"));

Criteria 집합

  • Group By 기본 사용법
/*
   select * from User
   group by name
*/

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Object[]> cq = cb.createQuery(Object[].class);
Root<User> user = cq.from(User.class);

cq.groupBy(user.get("name"));

TypedQuery<Object[]> query = em.createQuery(cq);
List<Object[]> resultList = query.getResultList();

Criteria 정렬

  • 내림차순, 오름차순 
    • cb.desc, cb.asc 
//select * from user where id = 1 order by age desc

...

cq.select(user)
  .where(id)
  .orderBy(cb.desc(user.get("age")));

Criteria IN

  • IN
    • where 뒤에 써준 컬럼과 in 뒤에 나열한 조건 중 일치한 row 를 가져오게 됩니다. 
/*
  select * from User
  where name in ("짱구", "흰둥이"))
*/

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> user = cq.from(User.class);

cq.select(user)
  .where(cb.in(user.get("name"))
  .value("짱구")
  .value("흰둥이"));

정리

Criteria API는 기존에 JPQL 에서 문자열로 나타날 수 있는 휴먼 에러등을 방지하고자 자바에서 객체 지향적으로 작성할 수 있는 Criteria API를 제공하게 되었습니다. 여기 작성된것 외에도 조인, 서브 쿼리, Case 등 여러가지가 있는데 추후에 유즈 케이스를 더 보게 되면 정리할 예정입니다. 

참고

  • https://milenote.tistory.com/137

'Spring' 카테고리의 다른 글

Spring Batch 멀티 프로세스  (1) 2024.09.09
스프링 핵심원리 고급편 - threadLocal, 템플릿 메서드 패턴 & 콜백 패턴  (0) 2024.01.14
의존성 주입  (1) 2023.01.21
Spring Security  (0) 2021.12.14
빈 생명주기 & 콜백  (0) 2021.12.14