오봉이와 함께하는 개발 블로그

JPA - 객체 지향 쿼리 언어 소개 본문

BE/JPA

JPA - 객체 지향 쿼리 언어 소개

오봉봉이 2022. 6. 29. 23:00
728x90

객체지향 쿼리 언어 소개

JPA로 모든 것을 해결할 수 없기 때문에 약점들을 보완하기 위해서 JPA는 다양한 쿼리 방법을 지원한다.
거의 대부분은 JPQL로 해결이 가능하지만 가끔 불가능한 경우는 네이티브SQL이나 MyBatis 등을 이용하자
다양한 쿼리 방법들은 아래와 같다

  • JPQL
  • JPA Criteria
  • QueryDSL
  • 네이티브SQL
  • JDBC API 직접 사용, MyBatis, SpringJdbcTemplate 함께 사용

JPQL 소개

  • 가장 단순한 조회 방법이다.
    • EntityManaget.find()
    • 객체 그래프 탐색(a.getB().getC())
  • 만약 조건이 필요해서 나이가 18살 이상인 회원을 모두 검색하고 싶다면?

JPQL

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

JPQL 단순한 예제

List<Member> memberList = em.createQuery(
        "select m from Member m where m.name like '%kim%'", 
        Member.class)
        .getResultList();

JPQL은 엔티티를 대상으로 쿼리하기 때문에 여기서 Member는 Member 테이블이 아니라 엔티티 Member를 가르킨다.

//검색
String jpql = "select m from Member m where m.age > 18"; 
List<Member> result = em.createQuery(jpql, Member.class) .getResultList();
-- 실행된  SQL
select
          m.id as id,
          m.age as age,
          m.USERNAME as USERNAME,
          m.TEAM_ID as TEAM_ID
from
Member m
      where
          m.age>18

Criteria 소개

JPQL은 결국 문자열이기 때문에 동적 쿼리를 구현하기 매우 까다롭고 불편하다.
그래서 Criteria가 나왔다.

문자가 아닌 자바코드로 JPQL을 작성할 수 있다. 자바 코드로 JPQL을 만들어주는 역할을 한다.

JPA의 공식 기능이지만 단점으로 너무 복잡하고 실용성이 없다.
그래서 Criteria 대신에 QueryDSL 사용을 권장한다.

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();

QueryDSL 소개

JPQL을 잘 알면 QueryDSL을 쉽게 사용할 수 있다.

  • 문자가 아닌 자바코드로 JPQL을 작성할 수 있어 JPQL을 만들어주는 역할을 한다.
  • 자바 코드로 작성하기 때문에 문법 오류를 찾을 수 있다.
  • 동적 쿼리 작성이 편리하다.
  • 단순하고 쉽기 때문에 실무 사용을 권장한다.

QueryDSL 단순한 예제

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

List<Member> list = query.select(m)
                          .from(m)
                          .where(m.age.gt(18))
                          .orderBy(m.name.desc())
                          .fetch();

네이티브 SQL 소개

  • JPA가 제공하는 SQL을 직접 사용하는 기능
  • JPQL로 해결할 수 없는 특정 DB에 의존적인 기능을 사용할 수 있다.
    • 오라클 CONNECT BY, 특정 DB만 사용하는 SQL 힌트

네이티브 SQL 단순한 예제

String sql =
    "SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME = ‘kim’";
List<Member> resultList =
            em.createNativeQuery(sql, Member.class).getResultList();

실제로 직접 작성한 쿼리가 날아가게 된다.

JDBC 직접 사용, SpringJdbcTemplate 등

  • JPA를 사용하며 JDBC 커넥션을 직접 사용하거나, 스프링 JdbcTemplate, MyBatis 등을 함께 사용 가능
  • 단, 영속성 컨텍스트를 적절한 시점에 강제로 flush() 필요하다.
    • persist()가 아니라, flush()가 되어야 DB에 데이터가 있기 때문에 적절한 시점에 강제로 플러시를 하지 않으면 원하는 결과가 나오지 않을 가능성이 다분하다.
      • flush()는 commit() 시점이나 createQuery(JPQL), createNativeQuery(네이티브 SQL)가 실행될 시점에 발생한다.
출처 : 인프런 김영한 지식공유자님의 스프링 부트와 JPA 실무 완전 정복 로드맵 강의
728x90

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

JPA - 프로젝션(select)  (0) 2022.06.30
JPA - 기본 문법과 쿼리 API  (0) 2022.06.30
JPA - 실전 예제 6 - 값 타입 매핑  (0) 2022.06.29
JPA - 값 타입 컬렉션  (0) 2022.06.29
JPA - 값 타입의 비교  (0) 2022.06.29
Comments