본문 바로가기
[JAVA]/JPA

JPA가 지원하는 다양한 쿼리 방법(JPQL, QueryDSL 등)

by 팡펑퐁 2023. 4. 22.
728x90

JPQL

  • JPA를 사용하면 엔티티 객체를 중심으로 개발하게 된다.
  • 문제는 검색 쿼리를 날릴 때이다. 테이블이 아닌 엔티티 객체를 대상으로 검색한다.
  • 모든 DB 데이터를 객체로 변환해서 검색하는 것은 현실적으로 불가능하다.
  • 애플리케이션이 필요로 하는 데이터만 DB에서 불러와야 한다.
  • 그러기 위해서는 결국 검색 조건이 포함된 SQL이 필요하다.
  • JPA는 SQL을 추상화한 JPQL이라는 객체지향 쿼리 언어를 제공한다.
    • SQL과 문법이 유사하며 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN을 지원한다.
    • JPQL은 엔티티 객체를 대상으로 쿼리를 만든다.
    • SQL은 데이터베이스 테이블을 대상으로 쿼리를 만든다.
    • SQL을 추상화하기 때문에 특정 데이터베이스 SQL에 의존하지 않는다.
    • 한마디로 객체지향 SQL이라고 할 수 있다.
    • SQL로 변환된다.

 

JPQL 문법

  • select m from Member as m where m.age > 18
  • 엔티티와 속성은 대소문자로 구분한다. (Member, age)
  • JPQL 키워드는 대소문자 구분을 하지 않는다.
  • 엔티티 이름을 사용한다.(Member)
  • 별칭은 필수로 넣어야 한다.(m)

 

 

집합과 정렬

  • COUNT() : 회원수
  • SUM() : 합계
  • AVG() : 평균
  • MAX() : 최대
  • MIN() : 최소
  • GROUP BY, HAVING
  • ORDER BY

 

 

TypeQuery, Query

TypedQuery<Member> query =
	em.createQuery("SELECT m FROM Member m", Member.class); // 타입이Member로 명확
  • TypeQuery : 반환 타입이 명확할 때 사용한다.
Query query =
	em.createQuery("SELECT m.username, m.age from Member m"); 
    // 타입이 String인지(username), int인지(age) 명확하지 않음
  • Query : 반환 타입이 명확하지 않을 때 사용한다.

 

 

결과 조회 API

query.getResultList()

  • 결과가 하나 이상일 때 리스트를 반환한다.
  • 결과가 없다면 빈 리스트를 반환한다.

query.getSingleResult()

  • 결과가 정확히 하나일 때만 단일 객체를 반환한다.
  • 결과가 없는 경우 javax.persistence.NoResultException,
  • 결과가 둘 이상일 경우 javax.persistence.NonUniqueResultException 에러가 발생한다.

 

파라미터 바인딩 - 이름 기준, 위치 기준

SELECT m FROM Member m where m.username=:username
query.setParameter("username", usernameParam);

 

SELECT m FROM Member m where m.uername=?1
query.setParameter(1, usernameParam);

위치 기준은 위치값이 변경되면 장애로 이어지기 때문에 이름 기준을 사용하자.

 

 

JPA Criteria

//Criteria 사용 준비
CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Member> query = cb.createQuery(Member.class);


//루트 클래스 (조회를 시작할 클래스)

Root<Member> m = query.from(Member.class);


//쿼리 생성 
CriteriaQuery<Member> cq = 
 
query.select(m).where(cb.equal(m.get("username"), “kim”)); 
List<Member> resultList = em.createQuery(cq).getResultList();
  • 문자가 아닌 자바 코드로 JQPL을 작성할 수 있다.
  • JPQL의 빌더 역할을 한다.
  • JPA 공식 기능이다.
  • 그러나, 너무 복잡하고 실용성이 없어 QueryDSL를 사용하는 것이 일반적이다.

 

 

QueryDSL

//JPQL
//select m from Member m where m.age > 18
JPAFactoryQuery query = new JPAQueryFactory(em);
 
QMember m = QMember.member;


List<Member> list = 
	query.selectFrom(m)

	     .where(m.age.gt(18)) 
         .orderBy(m.name.desc())
 
         .fetch();
  • 문자가 아닌 자바코드로 JQPL을 작성할 수 있다.
  • JPQL의 빌더 역할을 한다.
  • 컴파일 시점에 문법 오류를 찾을 수 있다.
  • 동적 쿼리 작성이 편리하다.
  • 단순하고 쉬워 실무에서 많이 사용된다.

 

 

 

네이티브 SQL

String sql =
    “SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME = ‘kim’ ";
    
List<Member> resultList =
            em.createNativeQuery(sql, Member.class).getResultList();
  • JPA가 제공하는 SQL을 직접 사용하는 기능이다.
  • JPQL로 해결할 수 없는 특정 데이터베이스에 의존하는 기능을 사용할 수 있다.
    • ex) 오라클의 CONNECT BY 등

 

 

 

JDBC 직접 사용, SpringJdbcTemplate 등

  • JPA를 사용하면서 JDBC 커넥션을 직접 사용하거나, 스프링 JdbcTemplate, Mybatis 등을 함께 사용가능하다.

 

 

 

참고

김영한 - 자바 ORM 표준 JPA 프로그래밍

728x90

'[JAVA] > JPA' 카테고리의 다른 글

JPQL - 페이징 API  (0) 2023.05.01
JPQL - 프로젝션  (0) 2023.05.01
JPA - 값 타입  (0) 2023.04.20
JPA - 영속성 전이: CASCADE와 고아 객체  (0) 2023.04.17
JPA - 즉시 로딩과 지연 로딩 사용시 주의할 점  (0) 2023.04.17