개발자꿈나무
JPQL - 기본 문법과 기능 본문
★ 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 안에 위치 값을 넣어주면 된다.
* 위치 기준 파라미터의 경우에는 위치가 변경될 우려가 있기 때문에 이왕이면 이름 기준 파라미터를 사용하는게 더 좋을듯하다.
'자바 > JPA' 카테고리의 다른 글
JPQL - 페이징 (0) | 2023.08.31 |
---|---|
JPQL - 프로젝션 (0) | 2023.08.31 |
객체지향 쿼리 언어 (0) | 2023.08.29 |
값 타입 컬렉션 (0) | 2023.08.28 |
값 타입과 불변 객체 (0) | 2023.08.23 |