반응형
특징
- JPQL은 객체지향 쿼리 언어다. 따라서 테이블을 대상으로 쿼리하는 것이 아니라 엔티티 객체를 대상으로 쿼리한다.
- JPQL은 SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다.
- JPQL은 결국 SQL로 변환된다.
기본 문법과 쿼리 API
JPQL도 SQL과 비슷하게 SELECT, UPDATE, DELETE 문을 사용 가능
(저장시, EntityManager.persist() 메소드를 사용하므로 INSERT는 존재하지 않음)
# JPQL 문법
# select문
select_
from_
[where_ ]
[group by_ ]
[having_ ]
[orderby_ ]
# update문
update_
[where_ ]
#delete
delete_
[where_ ]
SELECT 문
SELECT m FROM Member AS m WHERE m.username="corn"
- 대소문자 구분
- 엔티티와 속성은 대소문자를 구분한다. (Member, username 대소문자 구분)
- JPQL 키워드는 대소문자를 구분하지 않는다. (SELECT, FROM, AS)
- 엔티티 이름
- JPQL에서 사용하는 Member는 클래스 명이 아니라 엔티티 명이다. @Entity(name=xxx)
- 엔티티 명을 지정하지 않으면 클래스명을 기본값으로 사용한다.
- 별칭(Alias는 필수)
- Member AS m 처럼 Member에 m이라는 별칭을 주었는데, JPQL에서는 별칭을 필수로 사용해야 한다.
TypeQuery, Query
작성한 JPQL을 실행하기 위해선 쿼리 객체를 만들어야 한다.
- TypeQuery : 반환할 타입을 명확하게 지정할 수 있을 때
- Query : 반환 타입을 명확하게 지정할 수 없을 때
TypeQuery
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);
List<Member> resultList = query.getResultList();
for(Memeber member : resultList){
// ...
}
Query
Query query = em.createQuery("SELECT m FROM Member m");
List resultList = query.getResultList();
for(Object o : resultList){
Object[] result = (Object[]) o; // 결과가 여러개일 경우, 배열로 반환
System.out.println(result[0]); // username
System.out.println(result[0]); // age
}
파라미터 바인딩
1. 이름 기준 파라미터
이름 기준 파라미터는 앞에 :를 사용한다.
String usernameParam = "corn";
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m where m.username = :username", Member.class);
query.setParameter("username", usernameParam);
query.getResultList();
2. 위치 기준 파라미터
?다음에 위치 값을 준다.
위치 값은 1부터 시작한다.
String usernameParam = "corn";
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m where m.username = ?1", Member.class);
query.setParameter(1, usernameParam);
query.getResultList();
페이징 API
JPA는 우리의 편리한 사용을 위해 페이징 처리를 추상화해서 제공한다.
(데이터베이스마다 페이징을 처리하는 SQL 문법이 다르기 때문)
- setFirstResult(int startPosition) : 조회 시작 위치(0부터 시작)
- setMaxResults(int maxResult) : 조회활 데이터 수
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m ORDER BY m.username DESC", Member.class);
query.setFirstResult(10);
query.setMaxResults(20);
query.getResultList();
JPQL 조인
SQL 조인과 기능은 같고 문법만 약간 상이함.
(JPA 2.1부터는 ON절도 사용 가능하다.)
내부조인(INNER JOIN)
INNER는 생략 가능하다.
String teamName = "금융개발팀";
String query = "SELECT m FROM Member m INNER JOIN m.team t WHERE t.name = :teamName";
List<Member> memberList = em.createQuery(query, Member.class).setParameter("teamName", teamName).getResultList();
JPQL조인의 가장 큰 특징은 연고나 필드를 사용한다는 것인데, m.team이 연관 필드라고 할 수 있다.
연관 필드 : 다른 엔티티와 연관관계를 가지기 위해 사용하는 필드
FROM Member m JOIN m.team t // 회원이 가지고 있는 연관 필드로 팀과 조인
FROM Member m JOIN Team t // 오류남
외부조인(OUTER JOIN)
SELECT m
FROM Member m LEFT [OUTER] JOIN m.team t
페치 조인
폐치(fetch)조인은 JPQL에서 성능 최적화를 위해 제공하는 기능이다.
연관된 엔티티나 컬렉션을 한 번에 같이 조회하는 기능이며, join fetch
명령어로 사용할 수 있다.
SELECT m
FROM Member m JOIN FETCCH m.team
연관된 엔티티나 컬렉션을 함께 조회하게된다. 일반 JPQL조인과 다르게 별칭을 사용할 수 없다. (따라서 SELECT, WHERE 절, 서브 쿼리에 폐치 조인 대상을 사용할 수 없다.)
일반 조인 vs 폐치조인
둘의 차이점은 무엇일까?
실제 실행된 SQL을 보면 차이점을 알 수 있다.
-- 일반조인
SELECT m
FROM m INNER JOIN m.team t
-- 실행 SQL
SELECT
M.ID,
M.AGE,
M.TEAM_ID,
M.NAME,
FROM
MEMBERM M INNER JOIN TEAM T ON M.TEAM_ID = T.ID
-- Member 엔티티의 내용만 가져오게된다. 조인된 테이블(TEAM)의 내용은 가져오지 않는다.
-- 폐치조인
SELECT m
FROM Member m JOIN FETCCH m.team
-- 실행 SQL
SELECT
M.*, T.*
FROM
MEMBER M INNER JOIN TEAM T ON M.TEAM_ID = T.ID
-- 조인된 테이블(TEAM)의 컬럼내용도 가져온다. => TEAM 엔티티의 내용(필드)도 가져온다)
전체를 사용하지 않는 엔티티의 내용까지 로딩하므로 성능에 악영향을 미칠 수 있으나, SQL 호출 횟수를 줄여 성능이 최적화 될수도 있다.
Named 쿼리 : 정적쿼리
- 동적 쿼리 : em.createQuery( ...) 처럼 JPQL을 문자로 완성해서 직접 넘기는 것을 동적 쿼리라고 한다. 런타임에 특정 조건에 따라 JPQL을 동적으로 구성할 수 있다.
- 정적 쿼리 : 미리 정의한 쿼리에 이름을 부여해서 필요할 때 사용할 수 있는 것을 Named 쿼리라 한다. Named 쿼리는 한 번 정의하면 변경할 수 없는 정적인 쿼리다.
Named 쿼리의 장점
- 애플리케이션 로딩 시점에 JPQL 문법을 체크하고, 파싱해 두기 때문에 오류를 빨리 확인할 수 있으며, 파싱된 결과를 재사용하므로 성능상 이점이 있음
Named 쿼리를 어노테이션에 정의
// NamedQuery 설정
@Entity
@NamedQuery (
name ="Member.findByUsername",
query = "select m from Member m where m.username = :username")
public class Member{
...
}
// NamedQuery 사용시
List<Member> resultList =
em.createNamedQuery("Member.findByUsername", Member.class).setParameter("username", "corn").getResultList();
// 다중 NamedQuery 설정
@Entity
@NamedQueries({
@NamedQuery (
name ="Member.findByUsername",
query = "select m from Member m where m.username = :username"),
@NamedQuery (
name ="Member.findByTeamId",
query = "select m from Member m where m.teamId = :teamId")
})
public class Member{
...
}
그외 집계함수, 그룹핑, 서브쿼리 등은 SQL과 비슷
반응형
'프로그래밍 노트 > JPA' 카테고리의 다른 글
[JPA] 영속성 관리_1 (EntityManager, EntityManagerFactory, PersistContext) (0) | 2019.09.03 |
---|---|
[JPA] 스프링 데이터 JPA 소개 (0) | 2019.09.02 |
[JPA] 객체지향 쿼리 QueryDSL (0) | 2019.08.26 |
[JPA] JPQL이란? (0) | 2019.08.18 |
JPA, Hibernate, Spring Data JPA 구분하기 (차이점) (0) | 2019.07.23 |