Java / Spring

JPQL (JPQL기본기능, 결과조회 API, 쿼리의종류, 파라미터 바인딩) 본문

Spring/Spring Data JPA

JPQL (JPQL기본기능, 결과조회 API, 쿼리의종류, 파라미터 바인딩)

밍구밍구밍 2024. 5. 8. 19:14
JPQL 이란? (Java Persistence Query Language)
  • JPA 는 SQL을 추상화한 JPQL 이라는 객체 지향 쿼리 언어를 제공 한다.
  • SQL과 문법이 유사하고, SELECT, FROM, WHERE, GROUP BY, HAVIG, JOIN 지원
  • JPQL은 엔티티 객체를 대상으로 쿼리
  • SQL은 데이터베이스(DB) 테이블을 대상으로 쿼리

try {

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

    tx.commit();
}

 

 

  • 위의 JPQL 문법 중 Member 는 @Entity 속성이다.
  • Member 는 객체를 뜻하기 때문에 클래스에 선언된 대로 대소문자를 구분해야 한다. 마찬가지로 m.age 또한 클래스내의 변수를 초기화 한 것과 같이 대소문자를 구분해야 한다.
  • JPQL 키워드(select, from, where)는 대소문자 구분 하지 않아도 된다.
  • from 의 대상은 엔티티 이름을 사용한다 (Table 이름이 아니다)
  • 별칭은 필수(m) (as는 생략 가능)
** 쿼리의 종류 (TypeQuery / Query)

- TypeQuery 는 반환 타입이 명확할 때 사용

- Query 는 반환 타입이 명확하지 않을 때 사용

 

(사용 예 ↓)

Member member = new Member();
member.setUsername("member1");
member.setAge(10);
em.persist(member);

// 타입 쿼리 사용 (반환타입이 명확할 때) 
TypedQuery<Member> query1 = em.createQuery("select m.username from Member m", Member.class);// Member.class : 타입 정보

// 쿼리 사용 (반환타입이 명확하지 않을 때) = query 문에 String(username) 타입과 int(age) 타입이 동시에 사용될 때
Query query2 = em.createQuery("select m.username, m.age from Member m", Member.class);// Member.class : 타입 정보

 

 

 

*** 파라미터 바인딩

- 쿼리에 작성되는 특정 속성을 매개변수로 매핑 하는 것을 말한다.

- 쿼리에 매개변수를 매핑하는 방식에는 이름을 기준으로 하는 방식과 위치를 기준으로 하는 방식이 있다.

 

+ code Ex1) 이름 기반 바인딩

TypedQuery<Member> query1 = em.createQuery("select m from Member m where m.username = :username", Member.class);
query1.setParameter("username", "member1"); // 이름 기반 바인딩

이름 기준 바인딩=: (연산자) 를 사용

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

 

+ code Ex2 ) 위치 기반 바인딩

TypedQuery<Member> query1 = em.createQuery("select m from Member m where m.username = :? 1", Member.class);
query1.setParameter(1, "member1"); // 위치 기반 바인딩

- 위치 기준 바인딩=? (연산자) 를 사용

- 이름 기반 바인딩과 마찬가지로 메서드 체이닝 사용 가능

정리
  • 매개변수를 바인딩 할때는 이름 기반 바인딩을 사용 권장
  • 위치 기반 바인딩을 사용 하면 중간에 새로운 매개변수를 추가하는 경우, 순서가 밀리기 때문이다.
  • 또한, 숫자를 통해 어떤 위치의 매개변수가 무엇을 의미하는지 파악이 어렵다.
  • 가독성이 떨어지고, 유지보수성도 떨어진다.

-------------------------------------------------------------------------------------------------------------------------------------------------------

참조 1. Criteria (사용 권장 X)

CriteriaBulder() 생성 ( JAVA 표준 문법) - 특별한 상황 아닐 시 사용 권장하지 않는다

try {

    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"));
    em.createQuery(cq).getResultList();

    tx.commit();
}

 

** Criteria 코드의 장점 :

- 동적 쿼리 적용에 유리하다.

- 오타 시 컴파일 오류

- 문자가 아닌 자바 코드로 JPQL 작성 가능

 

** Criteria 코드의 단점 :

- 코드 복잡성으로 인해 유지보수성 & 실용성 ↓ 

- Criteria 대신 QueryDSL 사용 권장

 

참조 2. QueryDSL (오픈소스 라이브러리)

  • 하이버네이트 쿼리 언어의 쿼리를 타입에 안전하게 생성 및 관리해주는 프레임 워크
  • QueryDSL 은 정적 타입을 이용하여 SQL 과 같은 쿼리를 생성할 수 있게 해준다.
  • 복잡한 쿼리, 동적 쿼리 구현에 있어 한계가 존재한다.
  • QueryDSL 은 자바 코드로 SQL 문을 작성할 수 있어 컴파일 시에 오류를 발생하여 잘못된 쿼리가 실행되는 것을 방지할 수 있다.

 

참조 3. NativeQuery

try {

    Member member = new Member();
    member.setUsername("member1");
    em.persist(member);



    List<Member> resultList = em.createNativeQuery("select MEMBER_ID, city, street, zipcode, USERNAME from MEMBER", Member.class)
            .getResultList(); // em.createNativeQuery 이 시점에 flush() 동작

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


    tx.commit();

NativeQuery 를 하는 시점에 flush() 동작