Java

JPA 연관관계 설정 구체적인 방법 (fetch 타입 종류: LAZY, EAGER)

15호의 개발자 2022. 2. 25. 20:48
반응형

JPA 연관관계 설정 구체적인 방법 (fetch 타입 종류: LAZY, EAGER)

 

이전 글

 

[JPA] entity와 repository 생성 (+ JUnit Test 실행 방법)

[JPA] entity와 repository 생성 (+ JUnit Test 실행 방법) 이 게시글은 아래 글과 이어지는 글이다. JPA 연관관계 설정 (@OneToOne/@OneToMany/@ManyToOne/@ManyToMany) JPA 연관관계 설정 (@OneToOne/@O..

unit-15.tistory.com

 


 

이번에는 지난 번에 이어서 JPA로 연관관계를 설정하는 방법에 대해 알아보겠다. 쿼리문을 통해 연관관계를 설정하는 것이 아니라 JPA의 연관관계 어노테이션을 이용해서 구현하는 방법이다.

 

 

 

OrderDetail 엔티티

@Data
@NoArgsConstructor  // 기본 생성자
@AllArgsConstructor // 모든 매개변수를 가진 생성자
@Entity // 엔티티임을 명시, 자바는 카멜케이스이고 DB에 연결할 때는 스네이크케이스이므로 order_detail에 자동으로 연결
@ToString(exclude = {"user", "item"})
public class OrderDetail {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private LocalDateTime orderAt;
   
    @ManyToOne // N : 1
    private User user; // user_id
    
    @ManyToOne // N : 1
    private Item item;
    
}

OrderDetail 엔티티에 다음과 같이 user와 item을 선언해준다. 이때 @ManyToOne으로 연관관계를 설정해준 user와 item은 각각의 객체 타입으로 선언해야 한다.

 

 

@ToString
롬복을 쓰게 되면 toString을 자동으로 만들어주게 되는데, 이 부분에 대해서 orderDetail과 user가 서로 상호참조를 하고 있기 때문에 toString을 계속 타면서 오버플로우가 생기게 된다. 이 경우 @ToString 어노테이션을 사용해 user와 item을 제외시켜주면 서로 상호참조하고 있는 것이 풀리면서 에러가 생기지 않고 정상 작동한다.

 

 

 

User 엔티티

@Data   // 기본 생성자와 변수에 대해 get, set 메서드 생성
@AllArgsConstructor // 모든 매개변수를 가진 생성자도 추가
@NoArgsConstructor  // 파라미터가 없는 생성자 생성
@Entity // Entity임을 선언 (= table)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String account;

    private String email;

    private String phoneNumber;

    private LocalDateTime createdAt;

    private String createdBy;

    private LocalDateTime updatedAt;

    private String updatedBy;

    // 1 : N
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    private List<OrderDetail> orderDetailList;
    
}

User라는 클래스 안에 orderDetail 변수가 생겼고, mappedBy = "user"는 orderDetail 클래스 안에 있는 user라는 변수명과 매칭시킨다는 의미이다.

 

 

 

Item 엔티티

@Data   // 기본 생성자와 변수에 대해 get, set 메서드 생성
@AllArgsConstructor // 모든 매개변수를 가진 생성자도 추가
@NoArgsConstructor  // 파라미터가 없는 생성자 생성
@Entity // Entity임을 선언 (= table)
public class Item {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private Integer price;

    private String content;

    // 1 : N
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "item")
    private List<OrderDetail> orderDetailList;
    
}

Item이라는 클래스 안에 orderDetail 변수가 생겼고, mappedBy = "item"은 orderDetail 클래스 안에 있는 item이라는 변수명과 매칭시킨다는 의미이다.

 


JUnit Test 코드

이제 테스트 코드를 돌려보자.

public class UserRepositoryTest extends StudyApplicationTests {

    @Test
    @Transactional
    public void read() {
        Optional<User> user = userRepository.findById(1L);

        user.ifPresent(selectUser -> {
            // list형태로 상품이 반환됨. list이므로 stream을 통해 forEach를 돌림
            selectUser.getOrderDetailList().stream().forEach(detail -> { 
                
                Item item = detail.getItem();
                System.out.println(detail.getItem()); // ID 1인 사람의 detail에 있는 Item 객체를 출력
           
           });
        });
    }
    
}

UserRepositoryTest에 위와 같이 간단한 read() 메서드를 만들어보자. Id가 1인 user를 select 한 다음에 해당 user가 존재하면 해당 user의 OrderDetail를 List 형태로 받는다. 즉, 해당 user의 주문내역을 조회한다는 의미이다.

 


 

fetch 타입 종류

fetch 타입의 종류에는 LAZY와 EAGER가 있다.

 

  1. LAZY
    - 지연 로딩
    - 해당 변수에 대해 get 메소드를 호출하지 않는 이상 연관관계가 설정된 테이블에 대해서 SELECT를 하지 않는다.
  2. EAGER
    - 즉시 로딩
    - 연관 관계가 설정된 모든 테이블에 대해 JOIN이 일어난다.

 

데이터가 많은 테이블에 대해 EAGER 타입으로 설정되어 있다면, 쿼리문이 실행될 때 모든 테이블을 조인해서 가져오므로 성능에 문제가 생길 수 있다. 따라서 연관관계 설정에 대해서는 웬만하면 LAZY를 추천하고, EAGER는 1:1 관계라든지 연관관계에 있어서 한 건만 존재할 때만 사용하는 타입이다.

 


 

다음 글

 

[JPA] Query Method(쿼리 메소드) 사용 방법

[JPA] Query Method(쿼리 메소드) 사용 방법 QueryMethod(쿼리메소드)는 JPA에서 검색하는 방법 중 한 가지이다. public class UserRepositoryTest extends StudyApplicationTests { @Test @Transactional pu..

unit-15.tistory.com

 

 

 

(출처: 패스트캠퍼스 Java & SpringBoot로 시작하는 웹 프로그래밍)

반응형