[Spring JPA #7] JPA Fetch

2021. 3. 25. 03:16 Spring Data/Spring Data JPA

| JPA Fetch

 

JPA Fetch는 연관 관계의 엔티티를 어떻게 가져올 것인지를 정하는 정책입니다. Eager(초기) 혹은 Lazy(나중) 옵션을 지정하여 어떻게 연관 관계의 엔티티를 가져올 것인지를 정할 수 있습니다.

 

| JPA Fetch 예제 @OneToMany

 

프로젝트 구조

├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── tutorial
│   │   │           └── springbootjpa
│   │   │               ├── Account.java
│   │   │               ├── Address.java
│   │   │               ├── Comment.java
│   │   │               ├── JpaRunner.java
│   │   │               ├── Post.java
│   │   │               ├── SpringBootJpaApplication.java
│   │   │               └── Study.java
│   │   └── resources
│   │       ├── application.properties
│   │       ├── static
│   │       └── templates

 

의존성 관리

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

 

DB 저장 상태

springboot=# select * from post;
id |       title
----+-------------------
1 | Spring Data Title
(1 row)

springboot=# select * from comment;
id |      comment      | post_id
----+-------------------+---------
2 | Yes it is         |       1
3 | Great Spring Data |       1
(2 rows)

 

소스 코드

@SpringBootApplication
public class SpringBootJpaApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootJpaApplication.class, args);
    }

}
@Entity
public class Comment {

    @Id
    @GeneratedValue
    private Long id;

    private String comment;

    @ManyToOne
    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;
    }
}
@Entity
public class Post {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
    private Set<Comment> comments = new HashSet<>();

    public void addComment(Comment comment){
        this.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;
    }
}
@Component
@Transactional
public class JpaRunner implements ApplicationRunner {

    @PersistenceContext
    EntityManager entityManager;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        Session session = entityManager.unwrap(Session.class);
        Post post = session.get(Post.class, 1l);
        System.out.println("==================");
        System.out.println(post.getTitle());

    }
}

 

  • 위와 같이 데이터를 가져올 시, 연관 관계를 가지는 Commnet 엔티티에 대한 정보는 로딩하지 않고 Post 엔티티에 대한 정보만 가져오게 됩니다. 왜냐하면 @OneToMany 어노테이션은 FetchType.LAZY 가 Default로 설정되어 있기 때문에 Lazy 로딩이 되기 때문입니다.

 

결과 화면

Hibernate:
select
post0_.id as id1_2_0_,
post0_.title as title2_2_0_
from
post post0_
where
post0_.id=?

 

만일 

@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Comment> comments = new HashSet<>();

와 같이 FetchType.EAGER 옵션을 주게 될 경우 Post 엔티티와 연관된 모든 Comment 엔티티에 대한 정보를 가져오게 됩니다.

 

결과 화면

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=?

 

| JPA 예제 ManyToOne

 

소스 코드

@Component
@Transactional
public class JpaRunner implements ApplicationRunner {

    @PersistenceContext
    EntityManager entityManager;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        Session session = entityManager.unwrap(Session.class);
        Comment comment = session.get(Comment.class, 2l);
        System.out.println("==================");
        System.out.println(comment.getComment());
        System.out.println(comment.getPost().getTitle());
        
    }
}
  • 위와 같이 Comment 엔티티를 가져올 경우 자동적으로 그와 매핑되어 있는 Post 엔티티에 대한 정보를 가져오게 됩니다. 왜냐하면 매핑정보에 저장되어 있는 @ManyToOne 어노테이션은 FetchType.EAGER가 기본적으로 설정되어 있기 때문에 매핑되어 있는 연관된 엔티티에 대한 데이터를 로딩하기 때문입니다.

결과 화면

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=?
==================
Yes it is
Spring Data Title

 

https://www.inflearn.com/course/스프링-데이터-jpa



출처: https://engkimbs.tistory.com/818?category=772527 [새로비]