객체 지향 쿼리 언어

뚝딱이·2022년 9월 18일
0

JPA

목록 보기
9/11

JPA는 다양한 쿼리 방법을 지원한다.

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

JPQL

가장 단순한 조회 방법은 Entity Manager를 통해 find 하는 것과 객체 그래프 탐색(a.getB().getC())였다.

그런데 이때 나이가 18살 이상인 회원을 모두 검색하고 싶을 땐 find를 사용해서 검색할 수 없다.

JPA를 사용하면 엔티티 객체를 중심으로 개발해야하는데 문제는 검색 쿼리이다.
검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색한다. 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능하므로 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.

결국 DB에서 애플리케이션에 올릴 땐 최소한의 데이터만 가져와야한다.

이러한 문제를 해결하기 위해 JPA는 SQL을 추상화한 JPQL이라는 객체지향 쿼리언어를 제공한다. SQL과 문법 유사, SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원

  • JPQL은 엔티티 객체를 대상으로 쿼리
  • SQL은 데이터베이스 테이블을 대상으로 쿼리
em.createQuery(
                    "select m from Member m where m.username like '%kim%'",Member.class
            ).getResultList();
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_ 
        from
            Member member0_ 
        where
            member0_.USERNAME like '%kim%'

실제로 작성한 JPQL은 주석처리되고, 번역된 SQL문이 나가는 것을 볼 수 있다.

  • 테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리
  • SQL을 추상화해서 특정 데이터베이스 SQL에 의존X
  • JPQL을 한마디로 정의하면 객체 지향 SQL이라고 할 수 있다.

Criteria

JPQL의 쿼리문은 String이다. 따라서 동적인 쿼리를 만들기 어렵다. 전부 조건에 따라 문자열을 더해야하고, where문을 짤 때도 첫번째 where면 where를 붙이고 그다음부터는 and를 붙이는 등 굉장히 번거롭고 띄어쓰기등의 실수도 많이 발생할 수 있다.


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

이렇게 자바 코드로 sql을 짜면 오타를 내도 컴파일 오류가 나고, 동적 쿼리를 짜기에 굉장히 좋다. 하지만 복잡하고 어려우며 JPQL에 비해 한눈에 들어오지 않는다. 또한 SQL스럽지 않다.

사실 강사님은 실무에서 사용하지 않는다고 하셨다. 어렵고 복잡해 한눈에 알아보기 어려워 유지보수가 어렵다.

그래서 Criteria 보단 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();

한눈에 보기 쉽고, name에서 만약 neme 처럼 오타가 나도 컴파일에러가 나 문법 오류를 파악할 수 있다.

문자가 아닌 자바코드로 JPQL을 작성할 수 있다. 자바코드이기 때문에 재사용이 가능하고, 동적 쿼리 작성이 편리하다.

  • JPQL 빌더 역할
  • 컴파일 시점에 문법 오류를 찾을 수 있음
  • 단순하고 쉬움
  • 실무 사용 권장

네이티브 SQL

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

JDBC 직접 사용, SpringJdbcTemplate

  • JPA를 사용하면서 JDBC 커넥션을 직접 사용하거나, 스프링 JdbcTemplate, 마이바티스등을 함께 사용 가능
  • 단 영속성 컨텍스트를 적절한 시점에 강제로 플러시 필요, 왜냐면 이런 기술들은 JPA와 관련이 없기 때문, JPA와 관련이 있다면 쿼리가 나갈때 flush가 되는데, 없으면 flush가 되지 않아 commit하고 나서야 flush가 된다. 그래서 flush를 수동으로 실행해야한다.
  • 예) JPA를 우회해서 SQL을 실행하기 직전에 영속성 컨텍스트
    수동 플러시

출처 : 자바 ORM 표준 JPA 프로그래밍 - 기본편

profile
백엔드 개발자 지망생

0개의 댓글