Jpa 순환 참조 N + 1 문제
2024. 2. 27. 13:47ㆍSpring Boot
RestAPI를 만들려고 하던 중 이상한 오류가 발생 했다
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@RestController
@RequestMapping("mysql/rest")
public class my_rest_controller {
@Autowired
mySQLService service;
@RequestMapping(path ="/{id}", method=RequestMethod.GET)
public sqlEntity get_one_api() {
return service.all_data().get(0);
}
@RequestMapping(path = "/", method=RequestMethod.GET)
public List<sqlEntity> get_api() {
return service.all_data();
}
}


같은 값을 계속해서 출력하는 문제가 발생 한 것
@GetMapping()
public String all_data(Model model) {
model.addAttribute("testList", service.all_data());
return "db/mySQLBoard";
}

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Entity
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Table(schema = "sql_entity")
public class sqlEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String title;
@Column
private String data;
@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
private List<sqlChild> childs = new ArrayList<>();
sqlEntity(String title, String data) {
this.title = title;
this.data = data;
}
}
JSON으로 바꾸지 않고
그냥 Model에 값을 넣을 때는 문제가 없어서
JSON 변환 과정의 문제인 줄 알았는데
사용하는 Class에
@OneToMany로 매핑한 데이터가 문제였다.


이를 지우자 정상적으로 작동 했다.
좀 더 알아보니 이는 Jpa의 순환 참조 문제라고 한다.
Jackson은 Entity의 Getter 호출하고 직렬화를 이용해서 Json으로 변환하는데
이 과정에서 entity가 자신의 child에 값을 읽고
child는 다시 자신 부모 entity의 값을 읽고를 반복해서
무한하게 값을 읽게 된 것
해결 방안은
DTO를 하나 만들어서 필요한 데이터만 직접 return
참초하는 값에 @JsonIgnore을 붙이기
부모가 참조하는 필드에 @JsonManagedReference 붙이고 자식이 참조하는 필드에 @JsonBackReference 붙이기
부모 클래스이 @JsonIgnoreProperties 붙이기
양방향 매핑 끊기 등이 있다
@JsonIgnore
@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
private List<sqlChild> childs = new ArrayList<>();

'Spring Boot' 카테고리의 다른 글
| Spring Boot Studying (0) | 2024.02.28 |
|---|---|
| Authorization by Spring Security (0) | 2024.02.28 |
| CORS (1) | 2024.02.24 |
| Naver Login (0) | 2024.02.19 |
| Web Socket By STOMP (0) | 2024.02.19 |