경로 표현식

. 점을 찍어 객체 그래프를 탐색하는것

  • 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가지 기능 제공
      1. SQL에 DISTINCT를 추가
      1. 애플리케이션에서 엔티티 중복 제거


페치조인과 일반 조인의 차이

  • JPQL은 결과를 반환할때 연관관계 고려X
  • 단지 SELECT 절에 지정한 엔티티만 조회한다.
  • 페치 조인은 객체 그래프를 SQL 한번에 조회하는 개념
  • 페치 조인을 사용할 때만 연관된 엔티티도 함께 조회(즉시 로딩)


페치 조인의 특징과 한계

  • 페치 조인 대상에는 별칭을 줄 수 없다.
    • 하이버네이트는 가능하지만 가급적 사용하지 않는다.
  • 둘 이상의 컬렉션은 페치 조인 할 수 없다. ( 데이터 정합성에 안맞을수 있음)
  • 컬렉션을 페치 조인하면 페이징API를 사용할 수 없다.
  • 연관된 엔티티들을 SQL 한 번으로 조회 - 성능 최적화
  • 실무에서 글로벌 로딩 전략은 모두 지연 로딩
  • 최적화가 필요한 곳은 페치 조인 적용


페치 조인 - 정리

  • 페치 조인은 객체 그래프를 유지할 때 사용하면 효과적이다.
  • 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야하면, 페치 조인보다는 일반조인을 사용하고 필요한 데이터들만 조회해서 DTO로 반환하는것이 효과적이다.


벌크 연산

  • 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면?
  • JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL 실행
      1. 재고가 10개 미만인 상품을 리스트로 조회
      1. 상품 엔티티의 가격을 10% 증가
      1. 트랜잭션 커밋 시점에 변경감지가 동작한다.
  • 변경된 데이터가 100건이라면 100번의 update SPQ 실행해야함..

벌크 연산 예제

int resultCount = em.createQuery("update Member m set m.age = 20")
                    .executeUpdate();
  • 쿼리 한 번으로 여러 테이블 로우 변경(엔티티)
  • executeUpdate()의 결과는 영향 받은 엔티티 수 반환
  • UPDATE , DELETE 지원
  • INSERT(insert into …select..도 하이버네이트가 지원)

벌크 연산 주의 !

  • 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리
  • 해결법
    • 벌크 연산을 먼저 실행
    • 벌크 연산 수행 후 영속성 컨텍스트 초기화


😄 참고 : 인프런 김영한님의 JPA 기본 강의 및 교재

🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

개인메모

태그:

카테고리:

업데이트: