Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- MVC2
- Model2
- SQL
- AOP
- toUpperCase
- 기술 대비
- select
- 프레임워크
- 뉴렉처
- @Controller
- Model1
- 코테
- 자바
- DDL
- STS
- 메이븐
- 프로그래머스
- 서브쿼리
- 스프링
- 김영한
- 코딩테스트
- order by
- MVC
- JSP
- 인프런
- 세션
- 인텔리제이
- 서블릿
- @RestController
- Join
Archives
- Today
- Total
Heestory
🚀 JPA 프로젝트에서 DTO(Data Transfer Object)와 어노테이션 활용하여 순환 참조 해결하기 본문
JPA를 공부하면서 순환참조에 대해 제대로 이해가 되지 않았고, 나에게도 이런 문제가 생길까? 했는데 토이 프로젝트 과정 중 떡하니 바로 생긴 순환 참조 ㅎㅎ
이번 글에서는 ProductController에서 발생한 중복 데이터 반환 문제의 원인과 그 해결 방법을 알아본다.
✅ 1️⃣ 문제 원인 분석
📌 (0) 순환 참조 문제란?
양방향 관계에서 JSON 직렬화 시 무한 루프 발생
@Entity
public class Product {
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL)
private List<Review> reviews;
}
@Entity
public class Review {
@ManyToOne
@JoinColumn(name = "product_id")
private Product product;
}
📌 (1) 양방향 연관관계 순환 참조 문제
- JPA에서는 엔티티 간의 양방향 연관관계를 설정하였고, Product와 Review의 관계가 서로 참조
- Product → Review → Product로 순환 참조가 발생합니다.
- 이로 인해 JSON 직렬화 시 무한 루프에 빠지면서 중복 데이터가 무한히 반환되고 있음
📌 (2) 잘못된 Fetch 전략 설정 (EAGER 로딩)
- JPA의 기본 Fetch 전략은 LAZY이지만, EAGER로 설정 시 연관된 모든 데이터가 즉시 로딩
- 이로 인해 불필요한 데이터까지 포함되어 API 응답이 과도하게 커지는 문제가 발생합니다.
🚀 2️⃣ 해결 방법
✅ (1) 순환 참조 방지 설정
Product.java
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
@JsonManagedReference // 순환 참조 방지
private List<Review> reviews;
Review.java
@ManyToOne
@JoinColumn(name = "product_id", referencedColumnName = "id", nullable = false)
@JsonBackReference // 순환 참조 방지
private Product product;
- @JsonManagedReference: 직렬화 시 포함할 데이터로 유지
- @JsonBackReference: 직렬화 시 제외하여 무한 루프 방지
✅ (2) DTO로 데이터 반환하기
- DTO (Data Transfer Object): 데이터베이스의 엔티티(Entity)와 프론트엔드 간에 필요한 데이터만 전송하기 위해 사용되는 객체
- 엔티티 객체를 그대로 반환하면 해당 엔티티와 연관된 모든 데이터가 포함되기 때문에 엔티티 대신 필요한 필드만 포함한 DTO를 사용하여 응답 데이터를 관리
ProductDTO.java
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ProductDTO {
private Long id;
private String name;
private String description;
private double price;
private Integer stock;
public ProductDTO(Product product) {
this.id = product.getId();
this.name = product.getName();
this.description = product.getDescription();
this.price = product.getPrice();
this.stock = product.getStock();
}
}
✅ (3) 컨트롤러 수정
- Controller에서 Product 엔티티에 들어있는 불필요한 데이터 List<Preview>가 포함되지 않도록 함
ProductController.java
@GetMapping
public ResponseEntity<List<ProductDTO>> getAllProducts() {
List<ProductDTO> products = productService.getAllProducts().stream()
.map(ProductDTO::new) // Product → ProductDTO로 변환
.toList();
return ResponseEntity.ok(products);
}
✅ (4) 불필요한 데이터 로딩 방지 (Lazy 로딩 적용)
- 실제로 필요할 때만 데이터를 로딩되도록 Lazy 적
Product.java
@OneToMany(mappedBy = "product", fetch = FetchType.LAZY)
private List<Review> reviews;
이렇게 하여 순환참조를 해결하였다.
엔티티 관계를 좀 더 읽고 DTO를 잘 활용하도록 해야겠다.
'개발(0) > JPA' 카테고리의 다른 글
JPA 페이징 처리 (0) | 2025.02.07 |
---|---|
[IntelliJ]Querydsl 설치 (0) | 2023.08.25 |
[IntelliJ]JPA 프로젝트 개발시 에러 (0) | 2023.08.18 |