개발자꿈나무

JPQL - 기본 문법과 기능 본문

자바/JPA

JPQL - 기본 문법과 기능

망재이 2023. 8. 30. 15:17

★ JPQL 소개

- JPQL은 테이블을 대상으로 쿼리하는 것이 아니라 엔티티를 대상으로 쿼리하는 객체 지향 쿼리이다.

- JPQL은 SQL을 추상화해서 특정데이터베이스의 SQL에 의존하지 않는다.

- JPQL은 결국 SQL로 변환된다.

 

 

★ JPQL 기본 문법

기본적인 ANSI 표준 SQL은 전부 다 지원한다고 보면 된다. 문법 순서도 유사하다.

select문 = select절 from절 
	[where절] [groupby절] [having절] [orderby절]
    
update문 = update절 [where절]
delete문 = delete문 [where절]

- 엔티티와 속성은 대소문자를 구분한다.

- JPQL 키워드는 대소문자를 구분하지 않는다. (select, from ...)

- 엔티티 이름을 사용하며 테이블 이름이 아니다.

- 별칭은 필수이다. (as는 생략 가능)

-- 집합도 사용 가능 --
select 
    count(m),
    sum(m.age),
    avg(m.age),
    max(m.age),
    min(m.age)
from Member m;

 

 

★ TypeQuery, Query

  • TypeQuery : 반환 타입이 명확할 때 사용
  • Query : 반환 타입이 명확하지 않을 때 사용
TypedQuery<Member> query1 = em.createQuery("select m from Member m", Member.class);
TypedQuery<Integer> query2 = em.createQuery("select m.age from Member m", Integer.class);
Query query3 = em.createQuery("select m.age, m.userName from Member m");

query1은 Member 타입을 확실하게 반환할 수 있고, query2는 int를 반환할 수 있으므로 매개변수에 반환할 타입의 클래스를 명시해주고 TypeQuery로 받을 수 있지만 query3은 반환 타입이 int와 String 두 가지이므로 어느 하나를 명확하게 명시할 수 없다. 그럴 때 Query를 사용한다.

 

 

★ 결과 조회 API

  • query.getResultList() : 결과가 하나 이상일 때 리스트 반환
    반환할 결과가 없을 때는 빈 리스트 반환 -> NullPointException이 나지 않음
  • query.getSingleResult() : 결과가 정확히 하나일 때 단일 객체 반환
    결과가 없을 때는 NoResultException 발생
    하나 이상일 때는 NonUniqueResultException 발생
Member member1 = new Member();
member1.setAge(25);
member1.setUserName("User1");
em.persist(member1);

Member member2 = new Member();
member2.setAge(25);
member2.setUserName("User2");
em.persist(member2);

em.flush();
em.clear();

TypedQuery<Member> query1 = em.createQuery("select m from Member m where m.userName = 'User1'", Member.class);
TypedQuery<Member> query2 = em.createQuery("select m from Member m", Member.class);

Member result = query1.getSingleResult();
System.out.println("member.username = " + result.getUserName()); //단일 객체 반환

Member result2 = query2.getSingleResult();
System.out.println("member.username = " + result2.getUserName());

현재 member 테이블에는 User1, User2 두 명의 데이터가 존재하는 상태이다.

query1의 경우 이름이 User1인 회원에 대한 정보를 가져오는데 이때는 정확하게 한 명의 데이터만 가지고 오므로 getSingleResult를 사용해도 아무런 문제가 없다.

하지만 query2은 특정 조건 없이 member 테이블의 정보를 읽어오는 것이므로 결과가 하나가 아니게 된다. 이때 getSingleResult로 값을 받아오면 NonUniqueResultException이 발생한다.

 

 

★ 파라미터 바인딩 - 이름, 위치 기준

JDBC는 위치 기준 파라미터 바인딩만 지원하지만 JPQL은 이름 기준 파라미터 바인딩도 지원한다.

 

⭐︎ 이름 기준 파라미터

String name = "User1";
String jpql = "select m from Member as m where m.userName = :username"; //이름 기준 파라미터
List<Member> resultList = em.createQuery(jpql, Member.class)
        .setParameter("username", name)
        .getResultList();

이름 기준 파라미터는 앞에 : 를 사용하며 setParameter 안의 ""은 위에서 지정해준 : 이후의 이름과 같은 이름을 사용하여야 한다.

 

⭐︎ 위치 기준 파라미터

String jpql2 = "select m from Member m where m.userName = ?1";
List<Member> resultList2 = em.createQuery(jpql2, Member.class)
        .setParameter(1, name)
        .getResultList();

위치 기준 파라미터는 [:이름] 대신에 [?위치 값]를 사용한다. 위치 값은 1부터 시작하면 setParamete 안에 위치 값을 넣어주면 된다.

 

* 위치 기준 파라미터의 경우에는 위치가 변경될 우려가 있기 때문에 이왕이면 이름 기준 파라미터를 사용하는게 더 좋을듯하다.

728x90

'자바 > JPA' 카테고리의 다른 글

JPQL - 페이징  (0) 2023.08.31
JPQL - 프로젝션  (0) 2023.08.31
객체지향 쿼리 언어  (0) 2023.08.29
값 타입 컬렉션  (0) 2023.08.28
값 타입과 불변 객체  (0) 2023.08.23