01. JPQL 소개
JPQL 소개
JPQL은 객체지향 쿼리 언어이다. 따라서 테이블을 대상으로 쿼리하는 것이 아니라, 엔티티 객체를 대상으로 쿼리한다.
즉 @Entity(name = "")
에 name
에 해당하는 값을 말한다. 중요한 것은 JPQL은 SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다는 것이다. JPQL은 결국 SQL로 변환된다. (최대한 SQL문과 비슷하게 짜는 것이 좋다.)
02. JPQL 문법
JPQL 문법
예시로 select m from Member as m where m.age > 18
을 들 수 있다.
엔티티와 속성은 대소문자를 구분한다.
JPQL 키워드는 대소문자를 구분하지 않는다. (SELECT
, FROM
, WHERE
등) 엔티티 이름을 사용해야 한다. 테이블 이름이 아니다.
별칭은 필수이다. (예를 들어 m)
as는 생략이 가능하다.
집합과 정렬
GROUP BY, HAVING
ORDER BY
03. TypeQuery와 Query
TypedQuery와 Query
TypedQuery는 반환 타입이 명확할 때 사용하고, Query는 반환 타입이 명확하지 않을 때 사용한다.
아래는 예시 코드이다.
TypedQuery query1 = em.createQuery("select m from Member m", Member.class);
TypedQuery query2 = em.createQuery("select m.username from Member m", String.class);
Query query3 = em.createQuery("select m.username, m.age from Member m");
query2 같은 경우에, 반환 타입이 String 이라서 TypedQuery를 사용하는 반면, query3 같은 경우는 결과가 Integer와 String 타입으로 반환 타입이 명확하지 않으므로 Query를 사용한다.
04. 결과 조회 API
query.getResultList()
결과가 하나 이상일 때, 리스트를 반환하고, 결과가 없으면 빈 리스트를 반환한다. 아래는 예시 코드이다.
TypedQuery query = em.createQuery("select m from Member m", Member.class);
List resultList = query.getResultList();
for(Member members : resultList) {
System.out.println("member1 = " + members);
}
query.getSingleResult()
결과가 정확히 하나 일 때 사용하고, 단일 객체를 반환한다. 결과가 없다면 javax.persistence.NoResultException
이 발생한다. 결과가 둘 이상이라면 javax.persistence.NonUniqueResultException
이 발생한다. 아래는 예시 코드이다.
TypedQuery query = em.createQuery("select m from Member m where m.id=10", Member.class);
Member result = query.getSingleResult();
System.out.println("result = " + result);
아래는 결과가 없을 때를 보여준다.
이 예시를 테스트 하기 위해서는 persisten.xml의 property name="hibernate.hbm2ddl.auto" value="create" /> 로 설정하고, JpqlMain 에서 try 문 안에 넣었던 Member insert를 삭제한다.)
TypedQuery query = em.createQuery("select m from Member m", Member.class);
Spring Data JPA에서는 exception을 터뜨리지 않고 null 이나 optional 반환하도록 되어있다.
05. 파라미터 바인딩 - 이름 기준, 위치 기준
이름 기준
아래는 예시 코드이다.
TypedQuery query = em.createQuery("select m from Member m where m.username = :username", Member.class);
query.setParameter("username", "member1");
Member singleResult = query.getSingleResult();
System.out.println("singleResult = " + singleResult.getUsername());
결과로 select 쿼리문이 나가는 것을 볼 수 있다.
보통은 다음과 같이 메소드 체이닝을 사용한다.
Member result = em.createQuery("select m from Member m where m.username = :username", Member.class)
.setParameter("username", "member1")
.getSingleResult();
System.out.println("result = " + result.getUsername());
위치 기준
위치 기반의 파라미터 바인딩은 권장하지 않는다. 위치가 바뀌면 버그 발생 가능성이 있기 때문이다.
06. 기타
JPA는 값만 변경되면 트랜잭션 커밋 시점에 update가 날아간다. (단 이것은 하나씩 쿼리가 나가는 것이다.)
한번에 나가게 하려면 벌크 연산을 사용해야 하는데, 이것은 나중에 배운다.
'JPA' 카테고리의 다른 글
엔티티 작성 시 주의사항 (2) | 2024.01.30 |
---|---|
객체지향 쿼리 언어1 - 프로젝션 (SELECT) (0) | 2024.01.18 |
값 타입 컬렉션 (0) | 2024.01.18 |
값 타입의 비교 (0) | 2024.01.16 |
값 타입과 불변 객체 (2) | 2024.01.15 |