JPA 객체지향 쿼리 언어 - JPQL, QueryDSL 등 소개

2022. 7. 16. 17:44·공부/JPA
반응형

출처 : 자바 ORM 표준 JPA 프로그래밍 인프런 강의

 

JPA 게시글은 대부분 인프런의 김영한님의 강의인 '자바 ORM 표준 JPA 프로그래밍' 기반으로 내용을 정리했습니다.

 

객체지향 쿼리 언어(JPQL)

 

JPA는 다양한 쿼리 방법 지원

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

 

JPQL

  • 가장 단순한 조회 방법
    • EntityManager.find()
    • 객체 그래프 탐색
  • 나이가 18살 이상인 회원을 모두 검색하고 싶다면? 이런 경우에는 em.find()로 가져올 수가 없다.
  • JPA를 사용하면 엔티티 객체를 중심으로 개발
  • 문제는 검색 쿼리
  • 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
  • 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
  • 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요
  • JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공한다.
  • SQL과 문법이 유사하며 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN을 지원한다.(ANSI 표준 전부 지원)
  • JPQL은 엔티티 객체를 대상으로 쿼리한다.
  • SQL은 데이터베이스 테이블을 대상으로 쿼리한다.

 

조회

List<Member> result =  em.createQuery("select m From Member m where m.username like '%kim%'",
        Member.class).getResultList();
  • em.createQuery() 메서드를 이용해 JPQL을 사용할 수 있다.
  • get.ResultList()는 조회해 온 결과를 List로 만들어준다.
  • JPQL은 테이블이 아닌 객체를 대상으로 쿼리한다.

 

// 출력 로그
Hibernate: 
    /* select
        m 
    From
        Member m 
    where
        m.username like '%kim%' */ select
            member0_.MEMBER_ID as MEMBER_I1_6_,
            member0_.city as city2_6_,
            member0_.street as street3_6_,
            member0_.zipcode as zipcode4_6_,
            member0_.USERNAME as USERNAME5_6_,
            member0_.endDate as endDate6_6_,
            member0_.startDate as startDat7_6_ 
        from
            Member member0_ 
        where
            member0_.USERNAME like '%kim%'

 

JPQL을 한마디로 정의하면 객제 지향 SQL이다.

 


 

Criteria

  •  JPQL의 경우 쿼리가 String으로 이루어져있어 동적 쿼리를 만들기 어렵다.
  • 문자가 아닌 자바 코드로 JPQL을 작성할 수 있다.
  • JAVA 표준 문법에서 지원하는 기능이며  JPA 공식 기능이다.
// 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();
  • Criteria는 동적 쿼리를 쉽게 만들 수 있다.
  • JAVA 표준 문법이라 String 제외 메서드에서 오타가 날 시 에러 표시가 되어 에러를 찾기 쉽다.
  • 하지만 사용하기에 어려움이 있어 실무에서는 잘 사용하지 않는다. 
    • 복잡하여 유지보수가 어렵다.
  • 그래서 대신 QueryDSL 사용을 권장한다.

 

QueryDSL 소개

  • 문자가 아닌 자바코드로 JPQL을 작성할 수 있다.
  • JPQL 빌더 역할
  • 컴파일 시점에 문법 오류를 찾을 수 있다.
  • 동적 쿼리 작성이 편리하다.
  • 단순하고 쉽다.
  • 실무에서 사용하길 권장한다.
//JPQL
// select m from Member m where m.age > 18
JAPFactoryQuery query = new JPAQueryFactory(em);
QMember m = QMember.member;

List<Member> list =
		query.selectFrom(m)
        	 .where(m.age.at(18))
             .orderBy(m.name.desc())
             .fetch();
JPQL을 잘하면 QueryDSL는 쉽게 배울 수 있다.

 


 

네이티브 SQL 소개

  • JPA가 제공하는 SQL을 직접 사용하는 기능
  • JPQL로 해결할 수 없는 특정 데이터베이스에 의존적인 기능
    예) 오라클 CONNECT BY, 특정 DB만 사용하는 SQL 힌트
  • 잘 사용하지 않는다.
String query = "select MEMBER_ID, city, street, zipcode, USERNAME from MEMBER";
List<Member> resultList =
        em.createNativeQuery(query).getResultList();

 


 

JDBC 직접 사용, SpringJdbcTemplate 등

  • JPA를 사용하면서 JDBC 커넥션을 직접 사용하거나, 스프링 JdbcTemplate, Mybatis 등을 함께 사용 가능하다.
  • 단 영속성 컨텍스트를 적절한 시점에 강제로 플러시 해줘야한다.
    예) JPA를 우회에서 SQL을 실행하기 직전에 영속성 컨텍스트를 수동 플러시 한다.
Member member = new Member();
member.setUsername("member1");
em.persist(member);

// flush ->commit, query
String query = "select MEMBER_ID, city, street, zipcode, USERNAME from MEMBER";
List<Member> resultList =
        em.createNativeQuery(query, Member.class).getResultList();

for(Member member1 : resultList) {
    System.out.println("member1 = " + member1);
}

tx.commit();

위 코드는 정상적으로 작동되는 코드이다.

Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            Member
            (city, street, zipcode, USERNAME, endDate, startDate, MEMBER_ID) 
        values
            (?, ?, ?, ?, ?, ?, ?)
Hibernate: 
    /* dynamic native SQL query */ select
        MEMBER_ID,
        city,
        street,
        zipcode,
        USERNAME 
    from
        MEMBER
member1 = hellojpa.Member@5eccd3b9

위 출력 로그를 보면 select 하기 전에 먼저 flush가 된다. 그래야 persist() 한 것을 DB에 반영하고, 그 반영된 데이터 값을 가져올 수 있기 때문이다. 참고로 flush는 commit, query() 시 자동으로 동작한다.

그런데 조회 쿼리를 스프링 DB 커넥션 같은 걸 사용해서 조회를 할 때 문제가 생긴다. DB 커넥션은 JPA에서 관리하지도 않아 조회 전에 flush가 자동으로 동작하지 않아 persist()한 member는 아직 JPA 안에 있어, 제대로 된 데이터를 가져올 수가 없게된다. 그러니 조회 전에 강제로 flush를 날려줘야된다.

 

 

반응형
저작자표시 비영리 변경금지 (새창열림)
'공부/JPA' 카테고리의 다른 글
  • JPA 객체지향 쿼리 언어(JPQL) - 프로젝션(SELECT)
  • JPA 객체지향 쿼리 언어(JPQL) - 기본 문법과 쿼리 API
  • JPA 값 타입 - 값 타입 컬렉션
  • JPA 값 타입 - 값 타입의 비교
데부한
데부한
어차피 할 거면 긍정적으로 하고 싶은 개발자
    반응형
  • 데부한
    동동이개발바닥
    데부한
  • 전체
    오늘
    어제
    • 분류 전체보기 (307)
      • 방통대 컴퓨터과학과 (27)
        • 잡담 (9)
        • 3학년1학기 (17)
      • 프로젝트 및 컨퍼런스 회고 (1)
        • 프로젝트 (4)
        • 한이음 프로젝트 (0)
        • 회고 (3)
      • 공부 (165)
        • Spring (37)
        • JPA (71)
        • 인프런 워밍업 클럽_BE (10)
        • Java (6)
        • React.js (27)
        • 넥사크로 (11)
        • 기타 (3)
      • 알고리즘 (85)
        • 알고리즘 유형 (10)
        • 알고리즘 풀이 (57)
        • SQL 풀이 (18)
      • 에러 해결 (13)
      • 잡담 (7)
        • 국비교육 (2)
        • 구매후기 (5)
        • 진짜 잡담 (0)
  • 블로그 메뉴

    • Github
    • Linkedin
    • 홈
    • 방명록
    • 글쓰기
    • 관리
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    프로그래머스
    스프링부트
    SQL
    자바스크립트
    에러해결
    토이프로젝트
    백준
    react
    SpringBoot를 이용한 RESTful Web Service 개발
    인프런
    코딩테스트
    토비의스프링부트
    알고리즘
    전자정부프레임워크
    JPA
    RESTful
    QueryDSL
    개발자
    oracle
    운영체제
    egov
    Java
    기출문제
    방통대
    springboot
    Spring
    IT
    넥사크로
    MSA
    프론트엔드
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
데부한
JPA 객체지향 쿼리 언어 - JPQL, QueryDSL 등 소개
상단으로

티스토리툴바