Fetch : 연관 관계에 있는 Entity 를 어떻게 가져올 것인지에 대한 설정
- Eager : 지금 가져온다.
- Lazy : 나중에 가져온다.
@OneToMany 의 Fetch 정보는 Lazy 이다.
- Eager 일 경우 1 릴레이션의 Entity 정보를 가져올때 N 정보를 모두 가져와 불필요한 정보를 객체에 로딩하게 될 가능성이 높아서이다.
@Entity
public class Post {
@Id @GeneratedValue
private Long id;
private String title;
// Entity 를 관리할 때 참조하는 Comment Entity 도 Persistent 상태로 관리해주렴.
@OneToMany(mappedBy = "post", cascade = {CascadeType.ALL},fetch = FetchType.LAZY)
private Set<Comment> comments = new HashSet<>();
public void addComment(Comment comment){
comments.add(comment);
comment.setPost(this);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Set<Comment> getComments() {
return comments;
}
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
}
@ManyToOne 의 Fetch 정보는 Eager 이다.
- N 릴레이션의 Entity 정보를 가져올 때 1릴레이션과 관련된 정보를 가져올 수 있다.
@Entity
public class Comment {
@Id @GeneratedValue
private Long id;
private String comment;
@ManyToOne(fetch = FetchType.EAGER)
private Post post;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Post getPost() {
return post;
}
public void setPost(Post post) {
this.post = post;
}
}
@OneToMany 의 Fetch 전략은 LAZY 라고 했다.
- 1 릴레이션을 가지는 Post 를 이용해서 Select 쿼리를 돌리면 Comment Entity 정보는 가져오지 않는다.
@Component
@Transactional
public class JpaParentChileRunner implements ApplicationRunner {
@PersistenceContext
private EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
Session session = entityManager.unwrap(Session.class);
Post post = session.get(Post.class, 18L);
System.out.println("===================================");
System.out.println(post.getTitle());
System.out.println("===================================");
}
}
Hibernate:
select
post0_.id as id1_2_0_,
post0_.title as title2_2_0_
from
post post0_
where
post0_.id=?
===================================
Spring Data JPA 언제 보나.
===================================
Fetch 전략을 EAGER 로 돌린다면 어떻게 되는가.
- Post Entity 를 이용해서 Select 쿼리를 돌리면 Join 으로 Comment 테이블도 함께 가져와 참조되는 Entity 에도 데이터를 저장하게 된다.
@Entity
public class Post {
@Id @GeneratedValue
private Long id;
private String title;
// Entity 를 관리할 때 참조하는 Comment Entity 도 Persistent 상태로 관리해주렴.
@OneToMany(mappedBy = "post", cascade = {CascadeType.ALL},fetch = FetchType.EAGER)
private Set<Comment> comments = new HashSet<>();
public void addComment(Comment comment){
comments.add(comment);
comment.setPost(this);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Set<Comment> getComments() {
return comments;
}
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
}
DDL = left outer join 으로 미리 연관 Entity 정보까지 가져오는 모습을 보여준다.
Hibernate:
select
post0_.id as id1_2_0_,
post0_.title as title2_2_0_,
comments1_.post_id as post_id3_1_1_,
comments1_.id as id1_1_1_,
comments1_.id as id1_1_2_,
comments1_.comment as comment2_1_2_,
comments1_.post_id as post_id3_1_2_
from
post post0_
left outer join
comment comments1_
on post0_.id=comments1_.post_id
where
post0_.id=?
===================================
Spring Data JPA 언제 보나.
===================================
@ManyToOne 의 Fetch 전략은 EAGER 라고 했다.
- 셀렉트 쿼리를 사용할 때 이미 테이블이 Join 되어진 쿼리문을 사용하기 때문에 인스턴스에는 이미 Post에 대한 데이터가 저장되어 있다.
@Component
@Transactional
public class JpaParentChileRunner implements ApplicationRunner {
@PersistenceContext
private EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
Session session = entityManager.unwrap(Session.class);
Comment comment = session.get(Comment.class, 19L);
System.out.println("===================================");
System.out.println(comment.getPost().getTitle());
System.out.println("===================================");
}
}
DDL = left outer join 으로 1 릴레이션 정보까지 가져오고 있다.
Hibernate:
select
comment0_.id as id1_1_0_,
comment0_.comment as comment2_1_0_,
comment0_.post_id as post_id3_1_0_,
post1_.id as id1_2_1_,
post1_.title as title2_2_1_
from
comment comment0_
left outer join
post post1_
on comment0_.post_id=post1_.id
where
comment0_.id=?
===================================
Spring Data JPA 언제 보나.
===================================
Fetch 전략은 성능에 영향을 미친다.
- 객체에 불필요한 정보를 너무 많이 담게 되는 것을 주의해야한다.
- n + 1 문제가 일어날 수 있다.
@Component
@Transactional
public class JpaParentChileRunner implements ApplicationRunner {
@PersistenceContext
private EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
Session session = entityManager.unwrap(Session.class);
Post post = session.get(Post.class, 18L);
System.out.println("===================================");
System.out.println(post.getTitle());
System.out.println("===================================");
// 순회
post.getComments().forEach( c -> {
System.out.println("---------------------");
System.out.println(c.getComment());
});
}
}
DDL = n+1 문제를 일으키지는 않는 상태, 순회 상 하나의 Post 에 맞는 Comment 를 가져오면서 n + 1 문제가 될 것 같았으나 , post 릴레이션의 PK 로 관련 Comment 를 끌어오는 모습
Hibernate:
select
post0_.id as id1_2_0_,
post0_.title as title2_2_0_
from
post post0_
where
post0_.id=?
===================================
Spring Data JPA 언제 보나.
===================================
Hibernate:
select
comments0_.post_id as post_id3_1_0_,
comments0_.id as id1_1_0_,
comments0_.id as id1_1_1_,
comments0_.comment as comment2_1_1_,
comments0_.post_id as post_id3_1_1_
from
comment comments0_
where
comments0_.post_id=?
---------------------
빨리 보고 싶어요..
---------------------
곧 보여드릴게요.
'springframework > Spring Data JPA' 카테고리의 다른 글
Spring Data JPA 의 원리와 소개 (0) | 2020.11.14 |
---|---|
Query (0) | 2020.11.13 |
Cascade, Entity 상태 (0) | 2020.11.13 |
관계 맵핑, 1 : N (0) | 2020.11.13 |
Value 타입 맵핑 (0) | 2020.11.13 |