[JPA] 즉시 로딩, 지연 로딩
Updated:
1. 개요
JPA는 즉시 로딩과 지연 로딩을 통해 연관된 데이터를 함께 조회해 올지, 아니면 연관된 데이터는 사용하는 시점에 불러올지 정할 수 있다. 이번에는 즉시 로딩과 지연 로딩에 대해 알아보도록 하자.
2. 즉시 로딩 (EAGER)
연관된 데이터를 함께 조회해오는 것을 즉시 로딩(EAGER)이라고 한다. @ManyToOne, @OneToOne의 기본 값이 EAGER로 되어있는데, 즉시 로딩은 N+1 문제를 발생시킬 수 있으므로 가급적 지연 로딩을 사용해야 한다.
2-1. 예제 코드
[Team.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
[Member.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Team getTeam() {
return team;
}
public void setTeam(Team team) {
this.team = team;
}
}
Line 11 : @ManyToOne은 fetch 타입을 지정하지 않으면 default 값은 즉시 로딩(EAGER)
[JpaMain.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member1 = new Member();
member1.setUsername("member1");
member1.setTeam(team);
em.persist(member1);
em.flush();
em.clear();
Member m = em.find(Member.class, member1.getId());
System.out.println("m = " + m.getTeam().getClass());
System.out.println("==================");
System.out.println("teamName = " + m.getTeam().getName());
System.out.println("==================");
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
emf.close();
}
}
Line 23 : fetch 타입이 EAGER이므로 join을 통해 연관된 데이터 함께 조회
Line 24 : join으로 team 엔티티를 얻어왔으므로 team 클래스 출력
Line 27 : 앞으로 join으로 연관된 데이터를 함께 조회해왔으므로 추가쿼리 없이 값 출력
2-2. 실행 결과
3. 지연 로딩 (LAZY)
프록시를 통해 실제로 사용하는 시점에 연관된 데이터를 조회해오는 것을 지연 로딩(LAZY)이라고 한다.
3-1. 예제 코드
[Team.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
[Member.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Team getTeam() {
return team;
}
public void setTeam(Team team) {
this.team = team;
}
}
[JpaMain.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member1 = new Member();
member1.setUsername("member1");
member1.setTeam(team);
em.persist(member1);
em.flush();
em.clear();
Member m = em.find(Member.class, member1.getId());
System.out.println("m = " + m.getTeam().getClass());
System.out.println("==================");
System.out.println("teamName = " + m.getTeam().getName());
System.out.println("==================");
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
emf.close();
}
}
Line 23 : fetch 타입이 LAZY이므로 member만 조회
Line 24 : 현재 team은 프록시 객체임을 확인
Line 27 : 실제로 사용하는 시점에 team 테이블 조회 후 값 출력
Leave a comment