JPA와 객체지향 쿼리
JPA는 다양한 쿼리 방법을 지원
JPQL
-가장 단순한 조회 방법. -JPA에서 제공하는 공식 쿼리. ANSI 표준과 거의 비슷함 -JPA를 사용하면 엔티티 객체를 중심으로 개발 -문제는 검색 쿼리. 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색! -모든 DB데이터를 객체로 변환해서 검색하는 것은 불가능 → 검색 조건이 포함 된 SQL 필요
-JPQL은 엔티티 객체를 대상으로 쿼리 ↔ SQL은 데이터베이스 테이블을 대상으로 쿼리
//검색
String jpql = "select m from Member m where m.name like '%hello$'";
List<Member> result = em.createQuery(jpql, Member.class).getResultList();
Member m ( 멤버 테이블이 아니라, 멤버 엔티티를 가져오고 있음 )
-SQL을 추상화해서 특정 데이터베이스 SQL에 의존X -JPQL을 한 마디로 정의하면 객체 지향 SQL
//검색
String jpql = "select m from Member m where m.age>18";
List<Member> result = em.createQuery(jpql,Member.class).getResultList();
JPQL 문법. SQL과 비슷하다. select문 (select절,from절,groupby절,having절,orderby절), update문, delete문..
-SQL과 JPQL 차이 1. 엔티티와 속성은 대소문자 구분한다.(Member, username) 2. JPQL 키워드는 대소문자 구분 안한다(SELECT, FROM, where) 3. 엔티티 이름 사용! 테이블 이름 아님(Member) 4. 별칭은 필수(m)
-결과 조회 API query.getResultList(): 결과가 하나 이상, 리스트 반환 query.getSingleResult(): 결과가 정확히 하나( 단일 객체 반환, 하나 아니면 예외 발생)
-파라미터 바인딩→ 이름 기준, 위치 기준 ( 웬만하면 name쓰는 게 좋겠지? 숫자는 밀릴 수 있으니까) SELECT m FROM Member m where m.username =:username query.setParameter("username",usernameParam);
SELECT m FROM Member m WHERE m.username = ?1 query.setParameter(1, usernameParam);
-프로젝션(SELECT 절에 적는 거)
SELECT m FROM Member m → 엔티티 프로젝션 SELECT m.team FROM MEMBER m → 엔티티 프로젝션
SELECT username, age FROM Member m → 단순 값 프로젝션
+new 명령어 단순 값을 DTO로 바로 조회 : SELECT new jpabook.jql.UserDTO(m.username, m.age) FROM Member m
*DTO: (Data transfer object)
-페이징 API JPA는 페이징을 다음 두 API로 추상화 1. setFirstResult(int startPosition) : 조회 시작 위치 (0부터 시작) 2. setMaxResults(int maxResult) : 조회할 데이터 수
//페이징 쿼리
String jpq = "select m from Member m order by m.name desc";
List<Member> resultList = em.createQuery(jpql, Member.class)
.setFirstResult(20)
.setMaxResults(20)
.getResultList();
DB에 맞춰서 쿼리를 자연스럽게 짜줌.. 와웅...
오라클을 사용하면 오라클 쿼리를 만들어서 보낸다.
-집합과 정렬 COUNT,SUM,AVG,MAX,MIN 다 사용할 수 있음
-조인 *내부 조인: SELECT m FROM Member m [INNER] JOIN m.team t (엔티티로 조회하기 때문에 m안에 team 객체를 접근해야 함)
외부 조인: SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
-페치 조인(현업에서는 페치 조인 많이 사용합니다) 엔티티 그래프 한번에 조회하는 방법. 별칭을 사용할 수 없다! JPQL : select m from Member m join fetch m.team Member뿐만 아니라, Team까지 한방에 같이 조회해서 가져다 줌( 그래프 다 조회 됨 ) → (=) SELECT M.*, T.* FROM MEMBER T INNER JOIN TEAM T ON M.TEAM_ID=T.ID
String jpql = "select m from Member m join fetch m.team";
List<Member> members = em.creatQuery(jpql, Member.class).getResultList();
for(Member member : members){
//페치 조인으로 회원과 팀을 함께 조회해서 지연로딩(LAZY) 발생하지 않음
System.out.println("username = " + member.getUsername() + ", " +
"teamname = " + member.getTeam().name());
}
만약 해당 예시에서 페치 조인을 하지 않았다면? 지금 Member객체 10개를 루프 돌면서 한 개씩 쓰고 있잖아. 그리고 거기서 member.getTeam().name()해서 Team객체를 접근하고 있고. 그러면 루프가 10번 반복되는 동안 Team객체 접근하는 루프도 10번 돌겠지? 성능이 똥이 되겠지... (N+1문제라고 부름. 1번 쿼리 보냈는데 루프 갯수만큼 N번 더 돌려. 그래서 N+1 문제임)
Named 쿼리 - 어노테이션
@Entity
@NamedQuery(
name = "Member.findByUsername",
query = "select m from Member m where m.username = :username")
public class Member{
...
}
List<Member> resultList =
em.createNamedQuery("Member.findByUsername", Member.class)
.setParameter("username", "회원1")
.getResultList();
미리 @NamedQuery를 짜두는 것 이라고 생각하면 된다. 그냥 쓰면 될 걸 굳이 이렇게 사용하는 이유는 뭘까?
JPQL쓸 때 쿼리문은 문자이다. 만약 오타 생기면? 컴파일 시점에 오류? 잡을 수 없다. 애플리케이션 로딩 시점에 문제 잡을 수 있을까? 못 잡는다. (물론 실행시키면 알 수는 있지만..) @NamedQuery는 애플리케이션 로딩 시점에 다 Parsing시켜서 SQL로 바꾼다. 문법 오류가 있으면 애플리케이션 로딩 시점에 오류를 잡을 수 있다.
해당 포스팅은 T아카데미에서 진행한 김영한 강사님의 JPA 유튜브 강의를 듣고 정리한 것입니다 : )
https://www.youtube.com/watch?v=WfrSN9Z7MiA&list=PL9mhQYIlKEhfpMVndI23RwWTL9-VL-B7U
'Spring > JPA' 카테고리의 다른 글
JPA 기반 프로젝트 (0) | 2021.04.12 |
---|---|
JPA 내부 구조. 영속성 컨텍스트 (0) | 2021.04.12 |
JPA 연관관계 매핑 -양방향 매핑 (0) | 2021.04.11 |
JPA 연관관계 매핑-단방향 매핑 (0) | 2021.04.11 |
JPA 필드와 칼럼 매핑 (0) | 2021.04.11 |
Uploaded by Notion2Tistory v1.1.0