일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 7장 고급매핑
- 기능개발 python
- Kotlin in action 3장
- Kotlin
- 20055 컨베이어 벨트 위의 로봇
- 스프링 핵심 원리
- 스프링 핵심 원리 - 기본편
- Kotlin in action 10장
- 13460 구슬탈출 2
- 컨베이어 벨트 위의 로봇 Python
- Kotlin in action 6장
- 스프링 컨테이너와 스프링 빈
- Kotlin In Action
- 자바 ORM 표준 JPA 프로그래밍 7장
- 객체 지향 설계와 스프링
- KotlinInAction
- 코틀린인액션
- Python
- spring
- Kotlin in action 5장
- 싱글톤 컨테이너
- 20055
- 백준
- kotlin in action 정리
- 코틀린
- 스프링 핵심 원리 이해
- 백준 13460 Python
- 백준 20055 컨베이어 벨트 위의 로봇
- 코틸린인액션
- 고급매핑
- Today
- Total
기록하는 습관
[JPA] 객체지향 쿼리와 JPQL 본문
1. 기본 문법과 쿼리 API
Java Persistence Query Language(JPQL)은 엔터티 객체를 대상으로 하는 쿼리 언어로, SQL과 유사하지만 테이블이 아닌 엔터티에 대해 작동한다.
1.1 기본 문법
JPQL의 기본 문법은 다음과 같다:
SELECT <별칭 또는 엔터티명>
FROM <엔터티명>
WHERE <조건>
예)
SELECT e FROM Employee e WHERE e.department = 'IT'
이 쿼리는 'IT' 부서에 속한 모든 직원을 검색한다.
1.2 쿼리 API
JPQL은 EntityManager를 통해 실행된다. EntityManager는 엔터티를 관리하고 영속성 컨텍스트를 제공하는데, 이를 이용해 JPQL을 실행할 수 있다.
EntityManager em = // EntityManager를 얻는 코드
TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e WHERE e.department = 'IT'", Employee.class);
List<Employee> resultList = query.getResultList();
이렇게 얻은 resultList에는 쿼리 결과가 들어있다.
2. 파라미터 바인딩
파라미터 바인딩은 JPQL 쿼리에 동적인 값들을 전달하는 방법을 의미한다. 정적인 쿼리만으로는 한계가 있음.
2.1 위치 기반 파라미터 바인딩
가장 간단한 방법은 위치 기반 파라미터 바인딩이다. 쿼리 문자열 안에 ?1, ?2, 등의 플레이스홀더를 사용하고, 파라미터 인덱스에 해당하는 값을 지정한다.
TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e WHERE e.department = ?1", Employee.class);
query.setParameter(1, "IT");
List<Employee> resultList = query.getResultList();
2.2 이름 기반 파라미터 바인딩
이름 기반 파라미터 바인딩은 :파라미터명 형식을 사용한다. 가독성이 더 높고, 순서에 구애받지 않아 편리하다.
TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e WHERE e.department = :dept", Employee.class);
query.setParameter("dept", "IT");
List<Employee> resultList = query.getResultList();
2.3 위치 기반 vs. 이름 기반
선택은 개인의 취향이지만, 보통 이름 기반 파라미터 바인딩이 더 가독성이 좋다고 생각함.
3. 프로젝션
프로젝션은 JPQL에서 쿼리 결과로 가져올 데이터를 선택하는 방법이다. 불필요한 데이터를 가져오지 않고 필요한 부분만 선택하여 성능을 최적화할 수 있다.
3.1 엔터티 프로젝션
가장 간단한 프로젝션은 엔터티 자체를 선택하는 것이다.
TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e WHERE e.department = 'IT'", Employee.class);
List<Employee> resultList = query.getResultList();
이 경우에는 Employee 엔터티 전체를 가져오게 된다.
3.2 단일 값 프로젝션
만약 엔터티의 특정 필드만 필요하다면, 단일 값 프로젝션을 사용할 수 있다.
TypedQuery<String> query = em.createQuery("SELECT e.name FROM Employee e WHERE e.department = 'IT'", String.class);
List<String> resultList = query.getResultList();
위의 예시에서는 직원의 이름만을 가져오고 있다.
3.3 여러 값 프로젝션
여러 값을 한 번에 가져올 수도 있다. 그러나 이 경우는 Object[]나 Tuple을 사용해야 한다.
TypedQuery<Object[]> query = em.createQuery("SELECT e.name, e.salary FROM Employee e WHERE e.department = 'IT'", Object[].class);
List<Object[]> resultList = query.getResultList();
3.4 DTO 프로젝션
가장 권장되는 방법 중 하나는 DTO(Data Transfer Object)를 사용하는 것이다. 엔터티의 일부 필드만 필요한 경우 DTO를 활용하여 필요한 정보만 전달받을 수 있다.
TypedQuery<EmployeeDTO> query = em.createQuery("SELECT new com.example.EmployeeDTO(e.name, e.salary) FROM Employee e WHERE e.department = 'IT'", EmployeeDTO.class);
List<EmployeeDTO> resultList = query.getResultList();
4. 페이징 API
페이징은 대량의 데이터를 작은 일부분씩 나눠서 가져오는 기술로, 성능을 향상시키고 메모리 소비를 줄일 수 있다.
4.1 setFirstResult와 setMaxResults
setFirstResult는 가져올 결과의 시작 위치를 지정하고, setMaxResults는 가져올 최대 결과 수를 지정한다. 이 두 메서드를 사용하여 페이징을 구현할 수 있다.
int pageNumber = 1;
int pageSize = 10;
TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e WHERE e.department = 'IT'", Employee.class);
query.setFirstResult((pageNumber - 1) * pageSize);
query.setMaxResults(pageSize);
List<Employee> resultList = query.getResultList();
위의 예시에서는 1페이지에서 10개의 결과를 가져오고 있다.
4.2 페이징을 위한 쿼리 작성
쿼리 자체에서 페이징을 구현할 수도 있다. OFFSET과 LIMIT을 사용하는 방법이 있다.
int pageNumber = 1;
int pageSize = 10;
TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e WHERE e.department = 'IT' ORDER BY e.name")
.setFirstResult((pageNumber - 1) * pageSize)
.setMaxResults(pageSize);
List<Employee> resultList = query.getResultList();
이렇게 하면 데이터베이스에서 직접 페이징이 이루어진다.
5. 집합과 정렬
데이터를 검색하면서 종종 집합(집계) 함수를 사용하여 결과를 합치거나 통계를 내는 경우가 있다. 또한 정렬은 결과를 특정 기준에 따라 정렬하는 것으로, 보기 좋은 결과를 얻기 위해 중요하다.
5.1 집합 함수
JPQL에서는 다양한 집합 함수를 사용할 수 있다. 가장 일반적인 것은 COUNT, SUM, AVG, MIN, MAX 등이다.
TypedQuery<Long> countQuery = em.createQuery("SELECT COUNT(e) FROM Employee e", Long.class);
Long totalCount = countQuery.getSingleResult();
TypedQuery<Double> avgSalaryQuery = em.createQuery("SELECT AVG(e.salary) FROM Employee e", Double.class);
Double averageSalary = avgSalaryQuery.getSingleResult();
위의 예시에서는 COUNT와 AVG 함수를 사용하여 직원의 총 수와 평균 급여를 구하고 있다.
5.2 정렬
결과를 특정 기준에 따라 정렬하려면 ORDER BY 절을 사용한다.
TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e WHERE e.department = 'IT' ORDER BY e.salary DESC", Employee.class);
List<Employee> resultList = query.getResultList();
위의 예시에서는 IT 부서에 속한 직원들을 급여 기준으로 내림차순 정렬하고 있다.
6. 서브쿼리
- NOT EXISTS : 서브쿼리에 결과가 존재하면 참
- NOT IN : 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참
- ALL : 모두 만족하면 참
- ANY, SOME : 같은 의미, 조건을 하나라도 만족하면 참
- JPA는 SELECT, WHERE, HAVING절에서만 서브 쿼리 사용 가능
- FROM절의 서브 쿼리는 현재 JPQL에서 불가능 (조인으로 풀 수 있으면 풀어서 해결)
7. JPQL 타입
- 문자: 'HELLO', 'She''s'
- 숫자: 10L(Long), 10D(Double), 10F(Float)
- Boolean: TRUE, FALSE
- ENUM: jpabook.MemberType.Admin (패키지명 포함)
- 엔티티 타입: TYPE(m) = Member (상속 관계에서 사용)
8. JPQL 기본 함수
- CONCAT
- SUBSTRING
- TRIM
- LOWER, UPPER
- LENGTH
- LOCATE
- ABS, SQRT, MOD
- SIZE, INDEX
'스터디 > 자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글
[JPA] 예외 처리와 엔티티 비교 (1) | 2024.01.25 |
---|---|
[JPA] 스프링 데이터 JPA (2) (0) | 2023.12.14 |
[JPA] 9장 값 타입 (0) | 2023.10.25 |
[JPA] 복합키에서 equals () 및 hashCode () 구현 (0) | 2023.10.05 |