김영한 님의 "자바 ORM 표준 JPA 프로그래밍" 책을 정리한 포스팅 입니다.
1. Criteria
- JPQL을 편하게 작성하도록 도와주는 빌더 클래스 모음
- 컴파일 시점에 오류를 발견할 수 있음
- 동적 쿼리를 작성하기 편함
2. 기초
항목 | 설명 |
CriteriaBuilder |
Criteria 쿼리 생성을 위한 시작점
|
CriteriaQuery |
쿼리 전체 구조를 담는 객체
|
Root |
조회의 시작점 (FROM 절)
|
Predicate |
WHERE 조건 표현
|
Order |
ORDER BY 정렬 표현
|
예제
더보기
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> u = query.from(User.class);
query.select(u)
.where(cb.le(u.get("id"), 100))
.orderBy(cb.desc(u.get("name")));
3. 쿼리
분류 | 항목 | 설명 |
쿼리 생성
|
select, distinct, multiselect |
다양한 형태의 SELECT 문 지원
|
construct() | DTO 반환 | |
tuple() |
튜플 형태의 결과 반환
|
|
집합
|
groupBy() |
GROUP BY 절 구성
|
having() |
HAVING 절 구성
|
|
정렬 | orderBy() | 정렬 조건 추가 |
조인 | join(), fetch() |
JOIN 및 FETCH JOIN 구성
|
서브쿼리
|
subquery() | 서브 쿼리 생성 |
correlate() |
메인 쿼리의 엔티티를 서브 쿼리로 가져옴
|
|
IN 식 | cb.in(...).value(...) | IN 절 처리 |
CASE | selectCase().when().otherwise() | 조건 분기 |
파라미터 | cb.parameter() |
바인딩 파라미터 정의
|
함수 호출 | cb.function() |
네이티브 SQL 함수 호출
|
동적 쿼리 | Predicate 조건 누적 |
조건을 유동적으로 조립 가능
|
예제) 쿼리 생성
더보기
@Test
@Transactional
void select() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> u = query.from(User.class);
// SELECT u FROM User as u WHERE u.id <= 100 ORDER BY u.name DESC
query.select(u)
.where(cb.le(u.get("id"), 100))
.orderBy(cb.desc(u.get("name")));
TypedQuery<User> typedQuery = entityManager.createQuery(query);
List<User> resultList = typedQuery.getResultList();
for (User row : resultList) {
System.out.println("id: " + row.getId());
System.out.println("name: " + row.getName());
System.out.println("team id: " + row.getTeam().getName());
System.out.println();
}
}
@Test
@Transactional
void multiselect() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> u = query.from(User.class);
// SELECT DISTINCT u.id, u.get FROM User u
query.multiselect(u.get("id"), u.get("name")).distinct(true);
TypedQuery<User> typedQuery = entityManager.createQuery(query);
List<User> resultList = typedQuery.getResultList();
for (User row : resultList) {
System.out.println("id: " + row.getId() + ", name: " + row.getName());
}
}
@Test
@Transactional
void constructor() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<UserDto> query = cb.createQuery(UserDto.class);
Root<User> u = query.from(User.class);
query.select(cb.construct(UserDto.class, u.get("id"), u.get("name")));
TypedQuery<UserDto> typedQuery = entityManager.createQuery(query);
List<UserDto> resultList = typedQuery.getResultList();
for (UserDto row : resultList) {
System.out.println("id: " + row.getId() + ", name: " + row.getName());
}
}
@Test
@Transactional
void tuple() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createQuery(Tuple.class);
Root<User> u = query.from(User.class);
// SELECT DISTINCT u.id as id, u.name as username FROM User u
query.multiselect(
u.get("id").alias("id"),
u.get("name").alias("username")
);
TypedQuery<Tuple> typedQuery = entityManager.createQuery(query);
List<Tuple> resultList = typedQuery.getResultList();
for (Tuple row : resultList) {
Integer id = row.get("id", Integer.class);
String username = row.get("username", String.class);
System.out.println("id: " + id + ", name: " + username);
}
}
예제) 집합
더보기
@Test
@Transactional
void aggregation() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createQuery(Tuple.class);
Root<User> u = query.from(User.class);
query.multiselect(
u.get("team").get("name").alias("team_name"),
cb.count(u).alias("cnt")
)
.groupBy(u.get("team").get("name"));
TypedQuery<Tuple> typedQuery = entityManager.createQuery(query);
List<Tuple> resultList = typedQuery.getResultList();
for (Tuple row : resultList) {
System.out.println("team name: " + row.get("team_name", String.class) + ", count: " + row.get("cnt", Long.class));
}
}
예제) 정렬
예제) 조인
더보기
@Test
@Transactional
void join() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createQuery(Tuple.class);
Root<User> u = query.from(User.class);
Join<User, Team> t = u.join("team", JoinType.INNER);
query.multiselect(
u.get("name").alias("user_name"),
t.get("name").alias("team_name")
);
TypedQuery<Tuple> typedQuery = entityManager.createQuery(query);
List<Tuple> resultList = typedQuery.getResultList();
for (Tuple row : resultList) {
System.out.println("team name: " + row.get("team_name", String.class) + ", user name: " + row.get("user_name", String.class));
}
}
예제) 서브쿼리
더보기
@Test
@Transactional
void subquery() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> user = query.from(User.class);
Subquery<Double> subquery = query.subquery(Double.class);
Root<User> subUser = subquery.from(User.class);
subquery.select(cb.avg(subUser.get("age")));
query
.select(user)
.where(cb.lessThan(user.get("age"), subquery));
TypedQuery<User> typedQuery = entityManager.createQuery(query);
List<User> resultList = typedQuery.getResultList();
for (User data : resultList) System.out.println(data);
}
예제) IN
더보기
@Test
@Transactional
void in() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> user = query.from(User.class);
List<String> names = List.of("Stephen Curry", "Jimmy Butler");
query
.select(user)
.where(user.get("name").in(names));
TypedQuery<User> typedQuery = entityManager.createQuery(query);
List<User> resultList = typedQuery.getResultList();
for (User data : resultList) System.out.println(data);
}
예제) CASE
더보기
@Test
@Transactional
void case_keyword() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createQuery(Tuple.class);
Root<User> user = query.from(User.class);
Expression<Object> ageLabel = cb.selectCase()
.when(cb.lt(user.get("age"), 20), "Teen")
.when(cb.between(user.get("age"), 20, 29), "20s")
.otherwise("30+");
query.multiselect(
user.get("name").alias("user_name"),
ageLabel.alias("age_group")
);
TypedQuery<Tuple> typedQuery = entityManager.createQuery(query);
List<Tuple> resultList = typedQuery.getResultList();
for (Tuple row : resultList) {
System.out.println("[" + row.get("age_group", String.class) + "] " + row.get("user_name", String.class));
}
}
예제) 파라미터 바인딩
더보기
@Test
@Transactional
void parameter_binding() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> user = query.from(User.class);
query.select(user).where(cb.equal(user.get("name"), cb.parameter(String.class, "name")));
TypedQuery<User> typedQuery = entityManager.createQuery(query);
typedQuery.setParameter("name", "Stephen Curry");
List<User> resultList = typedQuery.getResultList();
for (User row : resultList) {
System.out.println(row);
}
}
예제) 함수 호출
더보기
@Test
@Transactional
void function_call() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createQuery(Tuple.class);
Root<User> user = query.from(User.class);
query.multiselect(
user.get("name").alias("name"),
cb.lower(user.get("name")).alias("lowercase"),
cb.length(user.get("name")).alias("length")
);
TypedQuery<Tuple> typedQuery = entityManager.createQuery(query);
List<Tuple> resultList = typedQuery.getResultList();
for (Tuple row : resultList) {
System.out.println(row.get("name") + " " + row.get("lowercase") + " " + row.get("length"));
}
}
예제) 동적 쿼리
더보기
@Test
@Transactional
void dynamic_query() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> user = query.from(User.class);
String searchName = "Stephen Curry";
Integer minAge = null;
List<Predicate> predicates = new ArrayList<>();
if (searchName != null) predicates.add(cb.equal(user.get("name"), searchName));
if (minAge != null) predicates.add(cb.greaterThanOrEqualTo(user.get("age"), minAge));
query
.select(user)
.where(cb.and(predicates.toArray(new Predicate[0])));
TypedQuery<User> typedQuery = entityManager.createQuery(query);
List<User> resultList = typedQuery.getResultList();
for (User row : resultList) {
System.out.println(row);
}
}
'Spring > Spring Data JPA' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 10-5. 객체지향 쿼리 언어: 객체지향 쿼리 심화 (0) | 2025.04.24 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] 10-4. 객체지향 쿼리 언어: Native SQL (0) | 2025.04.24 |
[자바 ORM 표준 JPA 프로그래밍] 10-1. 객체지향 쿼리 언어: JPQL (0) | 2025.04.24 |
[Spring Data JPA] 3-4. Specifications (0) | 2024.08.03 |
[Spring Data JPA] 4-1. Spring Data Extensions (1) (0) | 2024.08.02 |