[JPA] JQPL (2)
경로 표현식
. 점을 찍어 객체 그래프를 탐색하는것
- SELECT m.username -> 상태필드로 객체 그래프를 탐색했다.
- from Member m
- join m.team t -> 단일값 연관필드
- join m.orders o -> 컬렉션 값 연관 필드
- where t.name = ‘팀A’
경로 표현식 용어정리
- 상태 필드 : 단순히 값을 저장하기 위한 필드
- 연관 필드 : 연관관계를 나타내기 위한 필드
- 단일값 연관 필드 : @ManyToOne, @OneToOne, 대상이 엔티티 ( ex : m.team )
- 컬렉션 값 연관 필드 : @OneToMany, @ManyToMany, 대상이 컬렉션 ( ex : m.orders )
경로 표현식 특징
- 상태 필드 : 경로 탐색의 끝, 더 이상 탐색이 안됨
- 단일 값 연관 필드 : 묵시적 내부조인(inner join) 발생, 탐생 O ( m.team.. …멤버에서 팀으로 팀에서 네임 )
- 컬렉션 값 연관 필드 : 묵시적 내부조인 발생, 탐색 x
- FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색이 가능하다.
명시적 조인, 묵시적 조인
- 명시적 조인 : JOIN 키워드 직접 사용
- SELECT m FROM Member m join m.team t
-
묵시적 조인 : 경로 표현식에 의해 묵시적으로 SQL 조인 발생 (내부적 조인만 발생)
-
SELECT m.team FROM Member m
- select t.members.username from Team t - > 실패
- select m.username from Team t join t.members m - > 성공
**실무에선 명시적 조인을 사용하는것이 좋다 !! **
- 왜냐하면 select o.member.team from Order o -> 조인이 2번 발생한다.
- 조인은 sql 튜닝에 중요한 포인트고 묵시적 조인은 조인이 일어나는 상황을 한눈에 파악하기 어렵기 때문!
페치조인 - 중요
- SQL 조인의 종류가 아니다.
- JPQL에서 성능 최적화를 위해 제공하는 기능이다.
- 연관된 엔티티나 컬렉션을 SQL 한번에 함께 조회하는 기능!
- JOIN FETCH 명령어로 사용한다.
엔티티 페치 조인
- 회원을 조회하면서 연관된 팀도 함께 조회(SQL 한번에)
- SQL을 보면 회원 뿐만 아니라 팀(T.*)도 함께 SELECT됨
- JPQL : select m from Member m join fetch m.team
- SQL : SELECT M.* , T.* FROM MEMBER M 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.createQuery(jpql, Member.class)
.getResultList();
for (Member member : members) {
//페치 조인으로 회원과 팀을 함께 조회해서 지연 로딩X
System.out.println("username = " + member.getUsername() + ", " +
"teamName = " + member.getTeam().name());
}
컬렉션 페치 조인
- 일대다 관계, 컬렉션 페치 조인
- JPQL : select t from Team t join fetch t.members where t.name=’팀A’;
- SQL 상 : SELECT T., M. FROM TEAM T INNER JOIN MEMBER M ON T.ID=M.TEAM_ID WHERE T.NAME = ‘팀A’
페치조인과 DISTINCT
- SQL의 DISTINCT는 중복된 결과를 제거하는 명령
- JPQL의 DISTINCT 2가지 기능 제공
-
- SQL에 DISTINCT를 추가
-
- 애플리케이션에서 엔티티 중복 제거
-
페치조인과 일반 조인의 차이
- JPQL은 결과를 반환할때 연관관계 고려X
- 단지 SELECT 절에 지정한 엔티티만 조회한다.
- 페치 조인은 객체 그래프를 SQL 한번에 조회하는 개념
- 페치 조인을 사용할 때만 연관된 엔티티도 함께 조회(즉시 로딩)
페치 조인의 특징과 한계
- 페치 조인 대상에는 별칭을 줄 수 없다.
- 하이버네이트는 가능하지만 가급적 사용하지 않는다.
- 둘 이상의 컬렉션은 페치 조인 할 수 없다. ( 데이터 정합성에 안맞을수 있음)
- 컬렉션을 페치 조인하면 페이징API를 사용할 수 없다.
- 연관된 엔티티들을 SQL 한 번으로 조회 - 성능 최적화
- 실무에서 글로벌 로딩 전략은 모두 지연 로딩
- 최적화가 필요한 곳은 페치 조인 적용
페치 조인 - 정리
- 페치 조인은 객체 그래프를 유지할 때 사용하면 효과적이다.
- 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야하면, 페치 조인보다는 일반조인을 사용하고 필요한 데이터들만 조회해서 DTO로 반환하는것이 효과적이다.
벌크 연산
- 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면?
- JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL 실행
-
- 재고가 10개 미만인 상품을 리스트로 조회
-
- 상품 엔티티의 가격을 10% 증가
-
- 트랜잭션 커밋 시점에 변경감지가 동작한다.
-
- 변경된 데이터가 100건이라면 100번의 update SPQ 실행해야함..
벌크 연산 예제
int resultCount = em.createQuery("update Member m set m.age = 20")
.executeUpdate();
- 쿼리 한 번으로 여러 테이블 로우 변경(엔티티)
- executeUpdate()의 결과는 영향 받은 엔티티 수 반환
- UPDATE , DELETE 지원
- INSERT(insert into …select..도 하이버네이트가 지원)
벌크 연산 주의 !
- 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리
- 해결법
- 벌크 연산을 먼저 실행
- 벌크 연산 수행 후 영속성 컨텍스트 초기화
😄 참고 : 인프런 김영한님의 JPA 기본 강의 및 교재
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
개인메모