ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JPA에서의 쿼리 언어들
    JPA/JPQL 2023. 7. 13. 22:03

    JPA에서는 다양한 쿼리 언어들을 지원한다.

    1. JPQL
    2. JPA Criteria
    3. QueryDSL
    4. 네이티브 SQL
    5. JDBC API 직접 사용, MyBatis, SpringJdbcTemplate을 함께 사용

     

     

    1. JPQL

    JPA를 사용하면 엔티티 객체를 중심으로 개발을 진행하게 된다.

     

     

    문제는 검색 쿼리인데, 검색을 할 때에도 테이블이 아닌 엔티티 객체를 대상으로 검색해야 한다.

    모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능

    -> 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.

     

    이런 문제를 해결하기 위해서JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공

    • SQL과 문법 유사, SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN을 지원
    • JPQL은 테이블이 아닌 엔티티 객체를 대상으로 쿼리
    • SQL은 데이터베이스 테이블을 대상으로 쿼리
    • JPQL을 한마디로 정의하면 객체 지향 SQL이고, SQL을 추상화해서 특정 데이터베이스 SQL에 의존 X

     

    JPQL 문법

    ex) select m from Member as m where m.age > 18

    엔티티와 속성은 대소문자 구분 O (Member, age)
    JPQL 키워드는 대소문자 구분 X (SELECT, FROM, where)
    테이블 이름이 아니라 엔티티 이름 사용 (Member)
    별칭은 필수(m) (as는 생략가능)

     

     

    JPQL의 예시

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

    SQL과 문법이 다르고 Member는 엔티티 Member를 의미한다.

     

    JPQL을 작성하면 SQL로 변형시켜서 쿼리를 날려준다.

    String jpql = "select m from Member m where m.age > 18";
    List<Member> result = em.createQuery(jpql, Member.class)
        .getResultList();

    쿼리로 나가게 된 SQL문

    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

     

     

     

     

     

    2. JPA Criteria

    JPQL은 전부 string 타입의 형태이기 때문에 오타나 띄어쓰기 같은 것들에서 오류가 발생하면 알아차리기도 힘들고 번거롭다는 단점이 있다.

     

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

     

    JPA Criteria의 장점은 동적 쿼리를 JPQL보다 쉽게 작성할 수 있고, string 형태가 별로 없어서 오타가 나더라도 컴파일 시점에서 잡아주기 때문에 신경쓸 것이 적다는 것이다.

     

     

    Criteria 소개

    • 문자가 아닌 자바 코드로 JPQL을 작성할 수 있음
    • JPQL 빌더 역할, JPA 공식 기능
    • 단점 : 너무 복잡하고 실용성이 없다.
    • 바로 다음에 소개할 QueryDSL로 대체해서 사용하는 것을 권장함

     

     

    Criteria는 SQL스럽지 않고 간단한 코드는 괜찮지만 복잡한 코드는 이해하기가 훨씬 어렵기 때문에 실무에서는 JPA Criteria를 잘 사용하지 않는다고 한다.

    -> 유지보수가 굉장히 어려움

     

     

     

     

     

    3. QueryDSL

    JPAFactoryQuery query = new JPAQueryFactory(em);
    
    QMember m = QMember.member;
     
    List<Member> list = queryFactory
          .select(m)
          .from(m)
          .where(m.name.like("kim"))
          .orderBy(m.id.desc())
          .fetch();

    위의 코드가 QueryDSL의 예시이다.

     SQL과 유사하기 때문에 이해하기 쉽다는 장점과 동적 쿼리가 쉽다는 장점, 자바 코드이기 때문에 재사용이 가능하면서 오타가 발생할 시에는 컴파일 시점에서 잡아준다는 장점이 있다.

     

     

    QueryDSL 특징

    • 문자가 아닌 자바코드로 JPQL 작성 가능
    • JPQL 빌더 역할
    • 컴파일 시점에 문법 오류를 찾을 수 있음
    • 동적쿼리 작성 편리함
    • 단순하고 쉬움
    • 이러한 장점들 때문에 실무사용 권장

     

    QueryDSL은 JPQL을 쉽게 사용할 수 있게 해주며 추가 기능을 지원하는 것이기 때문에 JPQL 공부를 충분히 한 다음에 공부 해야한다.

     

    QueryDSL은 많이 사용하는 기능이기 때문에 이후에 따로 카테고리를 만들어서 집중적으로 공부를 하도록 하겠다.

     

     

     

     

     

    4. 네이티브 SQL

    JPA에서 SQL을 직접 사용하는 기능들을 제공한다.

     

    JPQL로 해결할 수 없는 특정 데이터베이스에 의존적인 기능이 필요할 때 사용한다.

    예) 오라클 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();

    em.createNativeQuery를 사용해서 진짜 네이티브 쿼리를 날려주면 된다.

     

     

     

    5. JDBC 직접 사용, SpringJdbcTemplate 등

     

    • JPA를 사용하면서 JDBC 커넥션을 직접 사용하거나, 스프링 JdbcTemplate, MyBatis 등을 함께 사용 가능
    • 단, 영속성 컨텍스트를 적절한 시점에 강제로 플러시 하는 것이 필요
    • 예) JPA를 우회해서 SQL을 실행하기 직전에 영속성 컨텍스트 수동 플러시

     

    JPA와 크게 관련없는 기술이기 때문에 자동으로 플러시 되지 않는다

    flush가 되는 시점 -> commit 될 때, 쿼리 나갈때(em.createQuery 등)

     

    따라서 em.flush(); 로 강제 플러시를 함께 해줘야한다는 주의점이 있다.

     

     

     

     

    JPQL과 QueryDSL로 안될 때에는

     

    4번이나 5번중에 자기에게 맞는 걸 사용하는 것 추천

    누구에게는 스프링에서 제공하는 JDBC가 편하고 누구에게는 반대일 수도 있음

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

    경로 표현식  (0) 2023.08.09
    조건식 (CASE)  (0) 2023.07.14
    서브 쿼리  (0) 2023.07.14
    페이징, 조인  (0) 2023.07.14
    프로젝션(SELECT)  (0) 2023.07.13
Designed by Tistory.