개발놀이터

JPQL 초급 본문

JPA/JPA

JPQL 초급

마늘냄새폴폴 2021. 8. 26. 06:37

*JPQL 

-테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리
-SQL을 추상화해서 특정 데이터베이스 SQL에 의존X
-JPQL을 한마디로 정의하면 객체 지향 SQL


JPQL이 해결해야할 가장 큰 문제점 = 동적쿼리

그에 따른 해결책 = Criteria, Querydsl

Criteria의 특징
-문자가 아닌 자바코드로 JPQL을 작성할 수 있음
-JPQL 빌더 역할
-JPA 공식기능
-치명적인 단점 : 너무 복잡하고 실용성이 없다.
-Criteria대신 Querydsl 사용 권장

Querydsl의 특징
-문자가 아닌 자바코드로 JPQL을 작성할 수 있음
-JPQL 빌더 역할
-컴파일 시점에 문법 오류를 찾을 수 있음
-동적 쿼리 작성 편리함
-단순하고 쉬움
-실무 사용 권장



*JPQL 소개
-JPQL은 객체지향 쿼리 언어이다. 따라서 테이블을 대상으로 쿼리하는 것이 아니라 엔티티 객체를 대상으로 쿼리한다.
-JPQL은 SQL을 추상화해서 특정 데이터에비스 SQL에 의존하지 않는다.
-JPQL은 결국 SQL로 변환된다


*JPQL 문법
em.createQuery("select m from Member m where m.age > 20"), Member.class);

-엔티티와 속성은 대소문자를 구분한다. (Member, age) 
-JPQL키워드는 대소문자를 구분하지 않는다. (select, from, where)
-엔티티 이름 사용, 테이블 이름이 아님(Member) 
-엘리어스 필수 (as는 생략가능)


*TypeQuery vs Query
TypeQuery : 반환 타입이 명확할 때 사용
TypeQuery<Member> query = em.createQuery("select m from Member m"), Member.class); => Member엔티티에 대한 반환타입

Query : 반환 타입이 명확하지 않을 때 사용
Query query = em.createQuery("select m.username, m.age from Member m"); => username = String / age = int 타입이 명확하지 않음


*결과 조회 API
1. getResultList() : 결과가 하나 이상일 때, 리스트를 반환한다. 결과가 없으면 빈 리스트 반환 
List<Member> findMember = em.createQuery("select m from Member m"), Member.class).getResultList();

2. getSingleResult() : 결과가 정확히 단 하나일 때 사용한다. 단일 객체 반환
Member findMember = em.createQuery("select m from Member m"), Member.class).getSingleResult();

getSingleResult를 주의해서 사용해야 하는 이유
-결과가 없으면 NoResultException이 발생하고
-둘 이상이면 NonUniqueResultException이 발생한다. 


*파라미터 바인딩 - 이름기준, 위치기준
em.createQuery("select m from Member m where m.username = :username").setParameter("username", "member1"); 이런식으로 사용 마치 jdbc의 PreparedStatement를 사용 하듯이 사용하면 된다. 


*프로젝션
-select 절에 조회할 대상을 지정하는 것
-프로젝션 대상 : 엔티티, 임베디드 타입, 스칼라 타입

ex)
select m from Member m -> 엔티티 프로젝션
select m.team from Member m -> 엔티티 프로젝션
select m.address from Member m -> 임베디드 타입 프로젝션
select m.username, m.age from Member m -> 스칼라 타입 프로젝션 (다 때려박은거)


*조인
1. 내부조인 (inner join)
2. 외부조인 (outer join)

1. 내부조인 
조인을 했을 때 하나라도 null이 있으면 결과로 출력을 안해줌
select m from Member m (inner) join m.team t -> SQL문과 다른 점은 엔티티를 대상으로 쿼리를 한다는 것

2. 외부조인
조인 했을 때 null이 있어도 결과로 출력해줌
select m from Member m left (outer) join m.team t

cf) on 절
조인을 할때 조인 대상을 필터링해준다.
select m from Member m left (outer) join m.team t on t.name = 'teamA' -> 팀이름이 teamA인 튜플을 골라준다


*서브 쿼리
JPQL에서도 서브 쿼리를 지원한다. 단 from 절에서의 서브쿼리는 지원하지 않는다.
select m from Member m where m.age (select avg(m2.age) from Member m2)

서브쿼리 지원 함수
-exists(subquery) : 서브쿼리에 결과가 존재하면 참
select m from Member m left join m.team t where exists(select t from t where t.name = 'teamA')
-all(subquery) : 모두 만족하면 참
select o from Order o where o.orderAmount > all(select p.stockAmount from Product p)
-any, some(subquery) : 조건을 하나라도 만족하면 참
select m from Member m where m.team = any(select t from Team t)
-in(subquery) : 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참

JPA 서브쿼리의 한계
-JPA는 where, having 절에서만 서브쿼리 사용 가능
-select 절도 가능 (하이버네이트에서 지원)
-from 절의 서브 쿼리는 현재 JPQL에서 불가능 (조인으로 풀 수 있으면 풀어서 해결)


*조건식 - case문
-기본 case문
select case when m.age <= 10 then '학생요금' when m.age >= 60 then '경로요금' else '일반요금' end from Member m

-단순 case문
select case t.name when 'teamA' then '인센티브110%' when 'teamB' then '인센티브120%' else '인텐티브105%' end from Team t

-coalesce : 하나씩 조회해서 null이 아니면 반환
select coalesce(m.name, '이름 없는 회원') from Member m

'JPA > JPA' 카테고리의 다른 글

JPA를 활용한 (XToOne) Restful API설계  (0) 2021.09.13
JPQL 중급  (0) 2021.08.26
값 타입  (0) 2021.08.26
지연로딩과 즉시로딩 (프록시)  (0) 2021.08.24
JPA 상속관계 매핑  (0) 2021.08.23