JPQL( Java Persistence Query Language )
JPQL 은 객체지향 쿼리 언어로, 테이블이 대상으로 하는 것이 아닌, 엔티티 객체를 대상으로 쿼리한다
JPQL 은 작성하고 실행하면 SQL 로 변환된다.
Member 은 엔티티이다.
Member m 처럼 별칭은 필수이다.
String jpql = "select m From Member m where m.name like ‘%hello%'";
TypeQuery : 반환 타입이 명확할 때 사용한다.
아래의 코드는 Member.class 로 반환타입이 명확하다.
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);
Query : 반환 타입이 명확하지 않을때 사용한다.
아래 코드는 m.username 은 String 타입, m.age는 Integer 타입으로 반환타입이 명확하지 않다.
Query query = em.createQuery("SELECT m.username, m.age from Member m");
query.getResultList() : 결과가 하나 이상일 때, 리스트를 반환한다.
- 결과가 없으면 빈 리스트를 반환한다. 예외를 발생하지 않으며, 컬렉션타입으로 NullPointException이 발생하지 않는다.
List<Member> resultMany = em.createQuery("select m from Member m", Member.class).getResultList();
System.out.println("resultMany = " + resultMany);
Hibernate:
/* select
m
from
Member m */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.team_id as team_id4_0_,
member0_.username as username3_0_
from
Member member0_
resultMany = []
query.getSingleResult() : 결과가 정확히 하나일때, 단일 객체를 반환한다.
- 결과가 없으면 NoResultException 예외발생
- 결과가 2개 이상이면 NonUniqueResultException 예외발생
Member resultOne = em.createQuery("select m from Member m", Member.class).getSingleResult();
System.out.println("resultOne = " + resultOne);
Hibernate:
/* select
m
from
Member m */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.team_id as team_id4_0_,
member0_.username as username3_0_
from
Member member0_
javax.persistence.NoResultException: No entity found for query
at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1555)
at jpql.JpaMain.main(JpaMain.java:27)
파라미터 바인딩
파라미터를 바인딩하는 방법은 2가지가 있다.
첫번째로, 파라미터를 이름으로 받는 방법이다.
List resultList = em.createQuery("select m from Member m where m.username =:username")
.setParameter("username", "member1")
.getResultList();
두번째로, 순서로 받는 방법이다.
해당 방법은 순서가 변하면 오류가 생길 수 있어서 지양하는 방법이다.
List resultList = em.createQuery("select m from Member m where m.username =?1")
.setParameter(1, "member1")
.getResultList();
프로젝션 -> 스칼라 타입 프로젝션
여러값 조회할때 사용하는 방법 (new 명령어로 조회)
public class MemberDTO {
private String username;
private int age;
public MemberDTO(String username, int age) {
this.username = username;
this.age = age;
}
패키지 명을 모두 적어주어야한다.
List<MemberDTO> result = em.createQuery("select distinct new jpql.MemberDTO(m.username, m.age) from Member m", MemberDTO.class)
.getResultList();
페이징
for (int i = 0; i < 100; i++) {
Member member = new Member();
member.setUsername("member" + i);
member.setAge(10 + i);
em.persist(member);
}
em.flush();
em.clear();
List<Member> result = em.createQuery("select m from Member m order by m.age desc", Member.class)
.setFirstResult(1)
.setMaxResults(10)
.getResultList();
System.out.println("result.size() = " + result.size());
for (Member member1 : result) {
System.out.println("member1 = " + member1);
}
tx.commit();
내림차순으로 1부터 시작했으므로 98~89까지 출력된다.
또한, 방언을 교체할 수 있어서, MySQL 또는 Oracle 로 변경해서 실행하면 알맞은 쿼리를 확인할 수 있다.
Hibernate:
/* select
m
from
Member m
order by
m.age desc */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.team_id as team_id4_0_,
member0_.username as username3_0_
from
Member member0_
order by
member0_.age desc limit ? offset ?
result.size() = 10
member1 = Member{id=99, username='member98', age=108}
member1 = Member{id=98, username='member97', age=107}
member1 = Member{id=97, username='member96', age=106}
member1 = Member{id=96, username='member95', age=105}
member1 = Member{id=95, username='member94', age=104}
member1 = Member{id=94, username='member93', age=103}
member1 = Member{id=93, username='member92', age=102}
member1 = Member{id=92, username='member91', age=101}
member1 = Member{id=91, username='member90', age=100}
member1 = Member{id=90, username='member89', age=99}
조인
내부조인
em.createQuery("select m from Member m join m.team t");
외부조인
em.createQuery("select m from Member m left join m.team t");
EX) 회원과 팀을 조인하면서, 팀 이름이 A 인 팀만 조인
-> 일반 SQL 문과 크게 다르지 않다.
em.createQuery("select m from Member m join m.team t on t.name = 'A'");
EX) 회원의 이름과 팀의 이름이 같은 대상 외부 조인
SELECT m, t FROM Member m LEFT JOIN Team t on m.username = t.name
++ 추가
복잡한 동적 쿼리는 QueryDSL 을 사용해서 해결한다.
JPAFactoryQuery query = new JPAQueryFactory(em);
QMember m = QMember.member;
List<Member> list =
query.selectFrom(m)
.where(m.age.gt(18))
.orderBy(m.name.desc())
.fetch();
- 문자가 아닌 자바 코드로 작성 가능
- 컴파일 시점에 문법 오류를 찾을 수 있다.
- 실무에서 자주 사용한다
'Spring > JPA' 카테고리의 다른 글
Querydsl 설정 (0) | 2022.10.09 |
---|---|
쿼리메소드 - 정렬처리 (0) | 2022.10.09 |
즉시로딩 지연로딩 (0) | 2022.09.27 |
JPA 프록시 (1) | 2022.09.26 |
상속관계 매핑 ( @Inheritance , @DiscriminatorColumn ) (0) | 2022.09.23 |
댓글