일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- EC2
- 테스트
- 2 > /dev/null
- appspec
- 추후정리
- 컨테이너실행
- ㅔㄴ션
- docker명령어
- 예약
- foreignkey
- AuthenticationEntryPoint
- MySQL
- Query
- 외부키
- 검색
- subquery
- application.yml
- 적용우선순위
- 커밋메세지수정
- 네이티브쿼리
- 서브쿼리
- 테스트메소드
- 메세지수정
- 참조키
- 포트
- appspec.yml
- querydsl
- WeNews
- 메소드명
- ubuntu
- Today
- Total
제뉴어리의 모든것
JPQL 문법, 내용정리 본문
특징
- 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과 비슷
'Spring Boot' 카테고리의 다른 글
@DATA 어노테이션 (0) | 2021.01.14 |
---|---|
@Query 사용시 Limit 지정 방법 (0) | 2021.01.14 |
JpaRepository (0) | 2021.01.13 |
엔티티 클래스와 JpaRepository를 이용하여 DB 생성과 조작 (0) | 2021.01.13 |
jUnit 개념, 특징, 어노테이션, 메서드 (0) | 2021.01.12 |