Spring 2주차. 심화과정 lv.2를 보완하고 lv.3을 진행했다. 거의 다 진행했는데 순환에러가 터져서 문제 해결한다고 몇시간을 날렸다. 오늘 TIL에는 JPA Repository의 메서드를 정리하고 언급한 순환에러 해결 방법을 정리해보겠다.
아래 처럼 Velog Markdown에서 테이블 표 편하게 만들어주는 사이트
https://tableconvert.com/markdown-generator
method | 기능 |
---|---|
save() | 레코드 저장 (insert, update) |
findOne() | primary key로 레코드 한건 찾기 |
findAll() | 전체 레코드 불러오기. 정렬(sort), 페이징(pageable) 가능 |
count() | 레코드 갯수 |
delete() | 레코드 삭제 |
메서드 이름 키워드 | 예시 | 설명 |
---|---|---|
And | findByEmailAndUserId(String email, String userId) | 여러필드를 and 로 검색 |
Or | findByEmailOrUserId(String email, String userId) | 여러필드를 or 로 검색 |
Between | findByCreatedAtBetween(Date fromDate, Date toDate) | 필드의 두 값 사이에 있는 항목 검색 |
LessThan | findByAgeGraterThanEqual(int age) | 작은 항목 검색 |
GreaterThanEqual | findByAgeGraterThanEqual(int age) | 크거나 같은 항목 검색 |
Like | findByNameLike(String name) | like 검색 |
IsNull | findByJobIsNull() | null 인 항목 검색 |
In | findByJob(String … jobs) | 여러 값중에 하나인 항목 검색 |
OrderBy | findByEmailOrderByNameAsc(String email) | 검색 결과를 정렬하여 전달 |
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion
(StackOverflowError) (through reference chain:
com.sparta.blogpostspring.entity.User["commentList"]->
org.hibernate.collection.internal.PersistentBag[0]->
com.sparta.blogpostspring.entity.Comment["post"]->
com.sparta.blogpostspring.entity.Post["user"]->
com.sparta.blogpostspring.entity.User["commentList"]-> ...
위와 같은 StackOverFlow 문제가 터졌다.
Entity에 private List<Post> postList로만 선언되어있어 new 처리
private List<Comment> commentList = new ArrayList<>(); 와 같이
new로 다 처리했다. 실수를 잘 처리했지만 이건 원인이 아니었다.
@OneToMany 정리
@OneToMany(mappedBy = "user")
private List<Post> postList = new ArrayList<>();
@OneToMany(mappedBy = "user")
private List<Comment> commentList = new ArrayList<>();
이렇게 겹치는 @OneToMany가 원인인가 싶어서 둘 중 하나도 없에보고, 둘 다 없에봤지만 원인이 아니었다.
public PostResponseDto(Post post) {
this.username = post.getUser().getUsername();
this.title = post.getTitle();
this.content = post.getContent();
this.id = post.getId();
this.createdAt = post.getCreatedAt();
this.modifiedAt = post.getModifiedAt();
List<Comment> comments = post.getCommentList();
if(comments != null){
List<CommentResponseDto> commentResponseDtoList = new ArrayList<>();
for (Comment comment : comments) {
commentResponseDtoList.add(new CommentResponseDto(comment));
}
// 아래는 댓글작성시간순으로 정렬
commentResponseDtoList.sort(Comparator
.comparing(CommentResponseDto::getCreatedAt).reversed());
this.commentList = commentResponseDtoList;
}
}
이렇게 DTO안에도 DTO로 값을 넣어주니 순환참조 문제가 사라졌다.
작업 중간에 생성자의 파라미터로 post와 comment List를 받아서 service쪽에서 정렬을 하기도 했지만 생성자 안에 파라미터로 하나만 받는게 더 깔끔한 것 같아서 이렇게 바꿨다.
알게된 것 : 유저-게시글-댓글 처럼 이어져있는 구조일때는 순환 참조 문제가 발생할 수 있으니
최종 response가 아니어도 다른 response의 중간단계일때도 DTO로 값을 옮겨주는 것이 좋다.
날짜정렬방법 참고사이트 여기서 정렬방법은 좀 더 공부해보자.