기본 문법과 쿼리 API
JPQL도 SQL과 비슷하게 SELECT, UPDATE, DELETE 문을 사용할 수 있다. 참고로 엔티티를 저장할 때는 EntityManager.persist() 메소드를 사용하면 되므로 INSERT 문은 없다.
select_문 :: =
select_절
from_절
[where_절]
[groupby_절]
[having_절]
[orderby_절]
update_문 :: = update_절 [where_절]
delete_문 :: = delete_절 [where_절]
SELECT 문
SELECT 문은 다음과 같이 사용한다.
SELECT m FROM Member AS m where m.username = 'Hello'
- 엔티티와 속성은 대소문자를 구분한다. (Member, username)
- SELECT, FROM, AS 같은 JPQL 키워드는 대소문자를 구분하지 않는다.
- Member는 클래스명이 아니라 엔티티명이다.
- 별칭이 필수이다.
작성한 JPQL을 실행하려면 쿼리 객체를 만들어야 한다. 쿼리 객체는 TypeQuery와 Query가 있는데 반환할 타입을 명확하게 지정할 수 있으면 TypeQuery 객체를 사용하고, 반환 타입을 명확하게 지정할 수 없으면 Query 객체를 사용하면 된다.
// TypeQuery 사용 (반환타입이 Member.class)
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);
List<Member> resultList = query.getResultList();
for(Member member : resultList) {
System.out.println("member = " + member);
}
// Query 사용
Query query = em.createQuery("SELECT m.username, m.age from Member m");
List resultList = query.getResultList();
for(Object o : resultList) {
Object[] result = (Object[]) o;
}
두 코드를 비교해보면 타입을 변환할 필요가 없는 TypeQuery를 사용하는 것이 더 편리한 것을 알 수 있다.
파라미터 바인딩
▽ 이름 기준 파라미터
파라미터를 이름으로 구분하는 방법이다. 앞에 : 를 사용한다.
String usernameParam = "User1";
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m where m.username = :username", Member.class);
query.setParameter("username", usernameParam); // 파라미터 바인딩
List<Member> resultList = query.getResultList();
// cf) 참고로 JPQL API는 대부분 메소드 체인 방식으로 설계되어 있어서 다음과 같이 연속해서 작성할 수 있다.
List<Member> members =
em.createQuery("SELECT m FROM Member m where m.username = ?1", Member.class)
.setParameter(1, usernameParam)
.getResultList();
▽ NEW 명령어
TypedQuery<UserDTO> query =
em.createQuery("SELECT new UserDTO(m.username, m.age) FROM Member m", UserDTO.class);
List<UserDTO> resultList = query.getResultList();
SELECT 다음에 NEW 명령어를 사용하면 반환받을 클래스를 지정할 수 있다. 또한 NEW 명령어를 사용한 클래스로 TypedQuery를 사용할 수 있어서 지루한 객체 변환 작업을 줄일 수 있다.
페이징 API
데이터베이스마다 페이징을 처리하는 SQL 문법이 다르다. JPA는 페이징을 다음 두 API로 추상화했다.
- setFirstResult(int startPosition) : 조회 시작 위치(0부터 시작한다.)
- setMaxResults(int maxResults) : 조회 할 데이터 수
TypesQuery<Member> query =
em.createQuery("SELECT m FROM Member m ORDER BY m.username DESC", Member.class);
query.setFirstResult(10);
query.setMaxResults(20);
query.getResultList();
FirstResult의 시작은 10이므로 11번째부터 시작해서 총 20건의 데이터를 조회한다. 따라서 11~30번 데이터를 조회한다. 데이터베이스마다 다른 페이징 처리를 같은 API로 처리할 수 있는 것은 데이터베이스 방언(Dialect) 덕분이다.
집합과 정렬
집합은 집합함수와 함께 통계 정보를 구할 때 사용한다.
select
COUNT(m),
SUM(m.age),
AVG(m.age),
MAX(m.age),
MIN(m.age)
from Member m
집합 함수
함수 | 설명 |
COUNT | 결과 수를 구한다. 반환 타입: Long |
MAX, MIN | 최대, 최소 값을 구한다. 문자, 숫자, 날짜 등에 사용한다. |
AVG | 평균값을 구한다. 숫자타입만 사용할 수 있다. 반환 타입: Double |
SUM | 합을 구한다. 숫자타입만 사용할 수 있다. |
- DISTINCT를 집합 함수 안에 사용해서 중복된 값을 제거하고 나서 집합을 구할 수 있다.
select COUNT( DISTINCT m.age ) from Member.m
- DISTINCT를 COUNT에서 사용할 때 임베디드 타입은 지원하지 않는다.
GROUP BY, HAVING
select t.name, COUNT(m.age), SUM(m.age), AVG(m.age), MAX(m.age), MIN(m.age)
from Member m LEFT JOIN m.team t
GROUP BY t.name
HAVING AVG(m.age) >= 10
정렬(ORDER BY)
select m from Member m order by m.age DESC, m.username ASC
'JPA' 카테고리의 다른 글
JPQL - 페치 조인(Fetch Join) (0) | 2023.10.12 |
---|---|
JPQL 조인 (2) | 2023.10.10 |
객체지향 쿼리 언어 소개 (0) | 2023.09.22 |
값 타입 (0) | 2023.09.22 |
영속성 전이: CASCADE (0) | 2023.07.31 |