JPA 연관관계 설정 구체적인 방법 (fetch 타입 종류: LAZY, EAGER)
이번에는 지난 번에 이어서 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가 있다.
- LAZY
- 지연 로딩
- 해당 변수에 대해 get 메소드를 호출하지 않는 이상 연관관계가 설정된 테이블에 대해서 SELECT를 하지 않는다. - EAGER
- 즉시 로딩
- 연관 관계가 설정된 모든 테이블에 대해 JOIN이 일어난다.
데이터가 많은 테이블에 대해 EAGER 타입으로 설정되어 있다면, 쿼리문이 실행될 때 모든 테이블을 조인해서 가져오므로 성능에 문제가 생길 수 있다. 따라서 연관관계 설정에 대해서는 웬만하면 LAZY를 추천하고, EAGER는 1:1 관계라든지 연관관계에 있어서 한 건만 존재할 때만 사용하는 타입이다.
(출처: 패스트캠퍼스 Java & SpringBoot로 시작하는 웹 프로그래밍)
'Java' 카테고리의 다른 글
[어드민 페이지 만들기] ERD 설계 & Table 생성 & Entity 생성 (0) | 2022.02.27 |
---|---|
[JPA] Query Method(쿼리 메소드) 사용 방법 (0) | 2022.02.25 |
[JPA] entity와 repository 생성 (+ JUnit Test 실행 방법) (0) | 2022.02.25 |
JPA 연관관계 설정 (@OneToOne/@OneToMany/@ManyToOne/@ManyToMany) (0) | 2022.02.25 |
JpaRepository를 활용한 CRUD 구현 방법 (자세한 설명) (0) | 2022.02.24 |