: .
을 찍어 객체 그래프를 탐색하는 것
select m.username
from Member m
join m.team t
join m.orders o
where t.name
m.username
→ 상태 필드
m.team
→ 단일 값 연관 필드
m.orders
→ 컬렉션 값 연관 필드
이렇게 3가지 필드가 있음
: 단순히 값을 저장하기 위한 필드
Ex. m.username
: 연관관계를 나타내기 위한 필드
@ManyToOne
, OneToOne
, 대상이 엔티티(Ex. m.team)
@OneToMany
, @ManyToMany
, 대상이 컬렉션(Ex. m.orders)
상태 필드 (state field): 경로 탐색의 끝. 탐색 X
m.username처럼 또 .
을 찍어 더 이상 들어갈 수 있는 곳이 없음
단일 값 연관 경로: 묵시적 내부 조인(inner join) 발생, 탐색 O
편해보이지만 조심해서 써야한다. 아니다,,
그냥,, 쓰지마라,,
컬렉션 값 연관 경로: 묵시적 내부 조인 발생, 탐색 X
- FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색 가능
select m from Member m join m.team t
select m.team from Member m
결국 실무에서는
- 가급적 묵시적 조인 대신 명시적 조인을 사용하자.
- 조인은 SQL 튜닝에 중요 포인트
- 묵시적 조인은 조인이 일어나는 상황을 한눈에 파악하기 어려움
: 중복이 싫으면 DISTINCT로 제거
📌 일대다 조인할 때 데이터가 뻥튀기 될 수 있다. 하지만 반대로 다대일 관계는 뻥튀기 되지 않는다.
select distinct t
from Team t join fetch t.members
where t.name = '팀A'
SQL에 DISTINCT를 추가하지만 데이터가 다르므로 SQL 결과에서 중복제거 실패
DISTINCT가 추가로 애플리케이션에서 중복 제거 시도
같은 식별자를 가진 Team 엔티티 제거
일반 조인 실행시 연관된 엔티티를 함께 조회하지 않음
JPQL은 결과를 반환할 때 연관관계를 고려하지 않고 단지 select 절에 지정한 엔티티만 조회할 뿐이다.
여기서는 팀 엔티티만 조회하고, 회원 엔티티는 조회하지 않는다.
페치 조인을 사용할 때만 연관된 엔티티도 함께 조회(즉시 로딩)
(사실상 즉시 로딩이 발생한다고 보면 된다. 지연 로딩을 지정해줬지만 페치 조인을 사용하면 페치 조인이 우선되므로 즉시로딩 된다.)
페치 조인은 객체 그래프를 SQL 한 번에 조회하는 개념
원칙적으로 페치 조인 대상에는 별칭을 줄 수 없다. (ex. ... as m where m.username)
하이버네이트는 가능. 가급적 사용 하지 않기.
둘 이상의 컬렉션은 페치 조인할 수 없다.
컬렉션을 페치 조인하면 페이징 API(setFirstResult
, setMaxResult
)를 사용할 수 없다.
일대일, 다대일 같은 단일 값 연관 필드들은 페치 조인해도 페이징이 가능하다.
하이버네이트는 경고 로그를 남기고 메모리에서 페이징(매우 위험)
연관된 엔티티들을 SQL 한 번으로 조회 → 성능 최적화
엔티티에 직접 적용하는 글로벌 로딩 전략보다 우선시
(글로벌 로딩 전략: @OneToMany(fetch = FetchType.LAZY
)
실무에서 글로벌 로딩 전략은 모두 지연 로딩
최적화가 필요한 곳은 페치 조인 적용
모든 것을 페치 조인으로 해결할 수는 없다. 페치 조인은 객체 그래프를 유지할 때 사용하면 효과적이다.
여러 테이블을 조인해 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야한다면 페치 조인보다는 일반 조인을 사용하고, 필요한 데이터들만 조회해 DTO로 반환하는 것이 효과적이다.
별로 중요한 내용 아님
: 미리 정의해서 이름을 부여해두고 사용하는 JPQL
@Entity
@NamedQuery(
name = "Member.findByUsername",
query = "select m from Member m where m.username = :username"
)
public class Member {
만약 재고가 n개 미만인 모든 상품의 가격을 m% 상승시키려면
JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL이 실행된다.
이렇게 변경된 데이터가 100건이라면 100번의 UPDATE SQL이 실행된다.
벌크 연산은 쿼리 한 번으로 여러 테이블 로우를 변경할 수 있다.
그러므로
JPA 너무 어려워,, 조만간 다시 듣는다,,