본문 바로가기

JPA

JPQL

JPA 에서는 여러가지 쿼리를 날리는 방법을 지원한다.

  • JPQL
  • JPA Criteria
  • QueryDSL
  • Native Query
  • JDBC Api 직접 사용 (Mybatis, Spring JDBC Template 등)

 

 

 

JPQL : 객체지향 SQL : Java Persistence Query Language

  • 테이블이 아닌 객체를 통하여 검색을 해야한다.
    • JPA 는 객체지향 ORM 이기 때문에.
  • EntityManager 는 find() 를 통해서 객체를 편하게 검색해올 수 있다. 하지만 이는 문제가 있다.
    • 조건이 포함되지 않은 검색이므로 불필요한 데이터를 가져와서 메모리 낭비가 발생한다.
    • 규모가 커지면 이는 성능에 나쁜 영향을 미칠 수 있다.
  • 따라서, 검색조건이  포함되고, 객체지향적인 쿼리가 필요하며 이것이 JQPL 이다.

 

Entity 객체를 대상으로한 표준 쿼리 문법을 제공하여, DB 방언으로 자동 변환하여 쿼리문을 날려준다.

이 JPQL 문법은 ANSI 쿼리문을 추상화한 쿼리문이기 때문에, 구조가 유사하다. -> 특정 DB에 의존적이지 않다. 

 

대락 아래와 같이 쓰인다.

 

List<Member> resultList =
	  em.createQuery("SELECT m FROM Member as m", Member.class)
      .getResultList();

 

  • 엔티티와 속성은 대소문자를 구분한다 -> 엔티티의 이름, 엔티티 속성의 이름을 그대로 써야한다. (ex. Member, name)
  • from, select 등의 키워드는 대소문자를 구분하지 않는다.
  • 별칭은 필수.
  • 엔티티의 이름은 @Entity(name = "") 속성이며, 기본값은 클래스의 이름이다.

 

JPQL 쿼리의 타입

  1. 반환값이 특정되는 경우 : TypeQuery
    1. createQuery(String var1, Class<T> var2) 를 사용한 경우
TypedQuery<JPQLMember> select_m_from_jpqlMember_m = 
	em.createQuery("select m from JPQLMember m", JPQLMember.class);

 

     2. 반환값이 특정되지 못하는 경우 : Query

              1. createQuery(String var) 를 사용한 경우

              2. select 하는 것이 컬럼이고, int String 등이 섞여 있어 특정하지 못하는 경우

 

// 1 번 경우
Query select_m_from_jpqlMember_ = em.createQuery("select m from JPQLMember as m");

// 2 번 경우
Query query = em.createQuery("select m.username, m.age from JPQLMember as m");

 

 

 

JPQL 쿼리 결과 받아오는 방법

위의 쿼리 타입으로 쿼리를 정의하면 다음의 함수를 통해 쿼리 결과를 받아올 수 있다.

  1. query.getResultList() : 결과가 하나 이상일 때. 리스트를 반환한다.
    1. 결과가 없다면 빈 리스트를 반환.
  2. query.getSingleResult() : 결과가 정확히 하나 일 때
    1. 하나도 없어도 에러, 두개 이상이라도 에러.
    2. JPA 스펙상 에러가 나도록 정의되어 있지만, Spring 단에서 에를 catch 하는 문구가 구현되어 있다.
      1. 따라서 Spring Data JPA 같은 곳에서는 에러가 아니라 빈 옵셔널이 반환된다.

 

 

파라미터 바인딩

where 절 같은 곳에서 조건을 검색하기 위한 파리미터 바인딩은, 변수명과 : 기호를 사용한다.

Query findQuery = em.createQuery("select m from Member as m where m.name = :username");
findQuery.setParameter("username", "kim");
Object singleResult = findQuery.getSingleResult();

 

또는 메서드 체이닝을 사용할 수 있다.

Object singleResult1 = em.createQuery("select m from Member as m where m.name = :username")
                .setParameter("username", "kim")
                .getSingleResult();

 

 

 

 

 

 

Criteria

  • 위의 예에서 볼 수 있는 createQuery 안의 JPQL 은 결국 문자열 이다.
  • 문자열이기 때문에 동적쿼리 를 만들기 어렵다.
  • 동적쿼리를 작성하게 해주는 자바 표준 문법이다.

 

장점

  • 자바 코드상으로 작성하기 때문에, 컴파일타임에 오류를 잡을 수 있다.
  • 동적 쿼리를 깔끔하게 작성할 수 있다.

단점

  • SQL 스럽지 않은 문법이라 보기 어렵다.
  • 복잡하다. 그래서 유지보수도 어렵다.

 

자바 표준 스펙인 Criteria 보다는 QueryDSL 이 훨씬 낫다.

같은 장점에 위의 단점도 보완해준다.

 

 

 

QueryDSL

  • 오픈소스 라이브러리.
  • 후에 따로 포스팅 예정.

 

Native SQL

  • Connected by 등 특정 DB 방언 등 필요한 상황에는 SQL 문을 직접 날릴 수 있다.
em.createQuery("쿼리문").getResultList();

 

 

JDBC API 직접사용

  • DB 커넥션을 직접 받아와서 사용할 수 있다.
  • 이 방법을 제외한 위의 모든 방법들은 EntityManager 를 이용한 방법이다. 하지만 이는 직접 커넥션을 이용한 방법이므로, 1차캐시, 영속성 컨텍스트 이런 개념이 포함되지 않는다.
    • 따라서, 적절한 시간에 flush() 명령을 직접 입력해야한다.

'JPA' 카테고리의 다른 글

JPQL - Select  (0) 2021.04.23
영속성 컨텍스트를 쓰면 좋은점  (0) 2021.04.14
Entity Manager, 영속성 컨텍스트  (0) 2021.04.13