JPQL - (기본 문법, 쿼리 API, 페이징 API, 집합과 정렬)

2023. 9. 25. 16:35JPA

반응형

기본 문법과 쿼리 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