관리 메뉴

제뉴어리의 모든것

JPQL 문법, 내용정리 본문

Spring Boot

JPQL 문법, 내용정리

제뉴어리맨 2021. 1. 14. 10:31

특징


  • 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] JPQL 문법, 내용정리 (tistory.com)