[JPA] 즉시 로딩과 지연 로딩
프록시 객체는 주로 연관된 엔티티를 지연 로딩할 때 사용
즉시 로딩 : 엔티티를 조회할 때 연관된 엔티티도 함께 조회
-설정방법 : @ManyToOne(fetch = FetchType.EAGER) //이미 ManyToOne에선 fetchType은 EAGER이 default
지연 로딩 : 연관된 엔티티를 실제 사용할 때 조회
-설정방법 : @ManyToOne(fetch = FetchType.LAZY)
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne(fetch = FetchType.EAGER) //**
@JoinColumn(name = "TEAM_ID")
private Team team;
..
실행코드 :
Member member = em.find(Member.class, memberId);
Team team = member.getTeam(); //객체 그래프 탐색
실제 em.find(Member.class, memberId);로 회원을 조회하는 순간 팀도 함께 조회
JPA 구현체는 즉시 로딩을 최적하하기 위해 가능하면 조인쿼리를 사용
SELECT
M.MEMBER_ID AS MEMBER_ID,
M.TEAM_ID AS TEAM_ID
M.USERNAME AS USERNAME,
T.TEAM_ID AS TEAM_ID,
T.NAME AS NAME
FROM
MEMBER M LEFT OUTER JOIN TEAM T
ON M.TEAM_ID = T.TEAM_ID
WHERE
M.MEMBER_ID =?
팀은 조인해서 쿼리 한 번으로 조회
NULL 제약조건과 JPA 조인 전략
즉시 로딩 실행 SQL에서 JPA가 INNER JOIN이 아닌 LEFT OUTER JOIN을 사용한다 현재 회원 테이블에 TEAM_ID 외래키는 NULL 값을 허용하기 때문에 팀에 소속되지 않는 회원이 있을 가능성이 있다.
따라서 팀에 소속하지 않은 회원과 팀을 INNER JOIN 하면 팀은 물론이고 회원 데이터도 조회할 수 없다.
그러나 OUTER JOIN보단 INNER JOIN이 성능과 최적화에서 더유리, INNER JOIN을 사용하기 위해선 외래 키에 NOT NULL 제약 조건을 설정하면 값이 있는것을 보장하기때문에 INNER JOIN이 사요됨 JPA에게 이러한 사실을 알려주기위해
@JoinColumn 에 nullable =false을 설정하면됨
@JoinColumn(nullable =true) : NULL 허용 외부조인 사용
@JoinColumn(nullable =true) : NULL 허용x 내부조인 사용
지연로딩(LAZY LOADING)
지연로딩을 사용하기 위해선 @ManyToOne의 fetch 속성을 FetchType.LAZY로 지정
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne(fetch = FetchType.LAZY) //**
@JoinColumn(name = "TEAM_ID")
private Team team;
..
}
Member member = em.find(Member.class, memberId);
Team team = member.getTeam(); //객체 그래프 탐색, 프록시객체
team.getName();//팀 객체 실제 사용
회원과 팀을 지연로딩으로 설정시 em.find(Member.class,memberId)를 호출하면 회원만 조회하고 팀은 조회 하지않음
대신에 team 멤버변수에 프록시 객체를 넣어둠
프록시객체는 실제 사용될 때까지 데이터 로딩을 미룸 그래서 지연로딩이라 함
em.find(Member.class)일때
SELECT * FROM MEMBER
WEHERE MEMBER_ID =memberId
team.getName() 호출로 프록시 객체가 초기화되면서 실행되는 SQL
SELECT * FROM TEAM
WHERE TEAM_ID = 'team1'
프록시와 즉시로딩 주의
• 가급적 지연 로딩만 사용(특히 실무에서)
• 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
• 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
• @ManyToOne, @OneToOne은 기본이 즉시 로딩 -> LAZY로 설정
• @OneToMany, @ManyToMany는 기본이 지연 로딩