10. 객체 지향 쿼리 언어1 - 기본
소개#
JPA는 다양한 쿼리 방법을 지원#
JPQL- JPA Criteria
 QueryDSL- Native SQL
 - JDBC API 직접 사용, MyBatis, SpringJdbcTemplate 함께 사용
 
JPQL 소개#
- 가장 단순한 조회 방법
- EntityManager.find()
 
 - 18상 이상인 사람 모두 불러오려면 어떻게?
 
JPQL#
- JPA를 사용하면 엔티티 객체 중심으로 개발 해야함
 - 문제는 검색 쿼리
 - 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
 - 앱이 필요한 데이터만 DB에서 불러오려면 결구 검색 조건이 포함된 SQL이 필요함!
 - JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공
 - JPQL은 엔티티 객체를 대상으로 쿼리
 - SQL은 테이블을 대상으로 쿼리
 JPQL 을 한마디로 객체 지향 쿼리
Criteria 소개#
Criteria 대신 QueryDSL 사용 권장
- JPQL을 문자열 더하는 문제가 옴
- 동적 쿼리로 전환하면 좋음
 
 - 그 대안으로 Criteria 나옴
 - 음 그런데 오히려 가독성이 떨어지는 것 같음
 
장점#
- 동적쿼리 생성 시 컴파일 시점에 잡아줄 수 있음
 - 동적쿼리를 짜기 편함
 
단점#
- SQL 스럽지 않음...
 - 실무에서 거의 안쓰신다고 함
 - 한두번 써봤는데 유지보수가 안됨...
 
QueryDSL 소개#
JPQL이 근본, 기승전 JPQL
- 문자가 아닌 자바코드로 JPQL을 작성할 수 있음
 - JPQL 빌더 역할
 - 컴파일시 오류검출 가능
 - 동적쿼리 작성이 편함
 - 단순하고 쉬움
 - 실무 사용 권장
 
Native SQL 소개#
- JPA가 제공하는 SQL을 직접 사용하는 기능
 - JPQL로 해결할 수 없는 특정 DB에 의존적인 기능
 
JDBC API 직접 사용, MyBatis, SpringJdbcTemplate 함께 사용#
- 직접 커넥션 얻어서 사용
 - JPA 쿼리들은 commit, query 시 flush 됨
- 영속성 컨텍스트를 플러시해야 후에 JdbcTemplate 을 문제없이 사용 가능
 
 
기본 문법과 쿼리 API#
JPQL (Java Persistence Query Language)
JPQL 문법#
select m from Member as m where m.age > 18- Entity와 속성은 대소문자 구분 O (Member, m.age)
 - JPQL 키워드는 대소문자 구분 X (SELECT, From, where)
 - 엔티티 이름(
@Entity(name = "")) 사용, 테이블 이름이 아님 - 별칭은 필수(m) (as 는 생략 가능)
 
집합과 정렬#
- group by, order
 - having
 
TypeQuery, Query#
- TypeQuery: 반환 타입이 명확할 때 사용
 - Query: 반환 타입이 명확하지 않을 때 사용
 
결과조회#
query.getResultList(): 결과가 하나 이상일 때- 결과가 없으면 빈 리스트 반환
 
query.getSingleResult(): 결과가 정확히 하나- 결과가 없으면: javax.persistence.NoResultException
 - 결과가 두개 이상이면: javax.persistence.NonUniqueResultException
 
- Spring Data JPA 에서는
- Exception 보단...
 - null이나 Optional 반환
 
 
파라미터 바인딩#
이름 기준#
위치 기준#
- ?1 이런 식으로 가능하나 권장하지 않음
 
프로젝션 (SELECT)#
- SELECT 절에 조회할 대상을 지정하는 것
 - 대상: 엔티티, 임베디드 타입, 스칼라 타입 (primitive type)
 - Entity
SELECT m FROM Member mSELECT m.team FROM Member m
 - Embedded
SELECT o.adress from Order o
 - Scalar
SELECT m.age FROM Member m
 - DISTINCT 로 중복 제거
 
여러 값 조회#
1. Query 타입 조회
2. Object[] 타입 조회
3. new 명령어 조회
- 패키지명을 다 적어야 한다는 단점이 있음
 - 순서와 타입이 일치하는 생성자 필요
 
페이징#
setFirstResult(int startPosition): 조회 시작 위치setMaxResults(int maxResult): 조회할 데이터 수
조인#
- 내부 조인
SELECT m FROM Member m [INNER] JOIN m.team t
 - 외부 조인
SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
 - 세타 조인
select count(m) from Member m, Team t where m.username = t.name- Member row * Team row만큼 Row가 나옴...
 
 
ON 절#
1. 조인 대상 필터링#
회원과 팀을 조인하면서, 팀 이름이 A인 팀만 조인
- JPQL
SELECT m, t FROM Member m LEFT JOIN m.team t on t.name = 'A'
 - SQL
SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.TEAM_ID=t.id and t.name='A'
 
2. 연관관계 없는 엔티티 외부 조인#
회원 이름과 팀의 이름이 같은 대상 외부 조인
- JPQL
SELECT m, t FROM Member m LEFT JOIN Team t on m.username = t.name
 - SQL
- 비슷함
 
 
서브 쿼리#
- 나이가 평균보다 많은 회원
 
select mfrom Member m where m.age > (select avg(m2.age) from Member m2)
- 한건이라도 주문한 고객
- 아래와 같이 하면 서브쿼리와 본 쿼리의 Member m을 공유해서 성능이 느려짐
select m from Member m where (select count(o) from Order where m = o.member) > 0 
 - 아래와 같이 하면 서브쿼리와 본 쿼리의 Member m을 공유해서 성능이 느려짐
 
서브 쿼리 예제#
팀 A 소속인 회원
전체 상품 각각의 재고보다 주문량이 많은 주문들
어떤 팀이든 팀에 소속된 회원
JPQL 서브 쿼리의 한계 ⭐️#
- JPQL 는 WHERE, HAVING 절에서만 서브 쿼리 사용 가능
 - SELECT 절도 가능 (하이버네이트 지원)
 FROM 절의 서브 쿼리는 현재 JPQL에서 불가능- 조인으로 풀 수 있으면 풀어서 해결
 - 앱에서 가져온걸 조립하거나, 쿼리를 여러개로 풀기도 함
 - 정안되면 native query
 
JPQL 타입 표현과 기타식#
- 문자: 
'Hello''What!' - 숫자: long 
20L, double20D, float20F - Boolean: 
TRUE,FALSE - ENUM: 
jpabook.MemberType.Admin(패키지명 포함)- setParameter로 대체할 수 있음
 
 - 엔티티 타입: 
TYPE(m)= Member (상속 관계에서 사용) 
그리고 표준 SQL 은 다 지원한다고 보면 됨
조건식 (CASE 등등)#
- COALESCE: null 이면 지정된 값 반환
 - NULLIF
 
JPQL 함수#
- CONCAT
 - SUBSTRING
 - TRIM
 - ...
 - SIZE, INDEX (JPA 용도)
- 컬렉션 크기 
select size(t.members) from Team t - INDEX 는 안쓰는게...
 
 - 컬렉션 크기 
 
사용자 정의 함수 호출#
- 사용자 정의함수를 직접 등록해서 쓸 수 있음
 - 보통 DB마다 기본적으로 제공하는 함수들은, Hibernate Dialect Function으로 등록되어 있었음
 group_concatfunction이 DB에 등록되어 있어야함
추가적으로#
- lombok 에 equals HashCode
 - JPQL, queryDSL
 - 의문사항 ElementCollection