문제
- Cannot call sendError() after the response has been committed
- Spring Lv.3 개인 과제를 진행하는 도중, 프로젝트를 실행해보았는데, 게시글 안의 댓글을 작성하고 게시글을 조회하자 조회가 안되는 문제가 발생
- 댓글을 작성하기 전까지는 게시글 조회에 문제가 없었는데 댓글을 작성하자 에러가 나는 걸로 보아서 댓글 작성 기능에서 문제가 생긴 것으로 보인다.
- 게시글 지워지면 댓글도 지워지는 기능
- 댓글이 게시글에 포함되어 있기 때문에, 댓글이 지워지면 게시글도 지워주어야 함
시도
- Cannot call sendError() after the response has been committed
- 어떤 문제가 있는지 확인해보기 위해서 디버깅을 진행
- Post안에 commentList에 Comment를 저장하는 것까지는 문제가 없었다.
- 하지만 commentList를 살펴보자 그 안에 Post가 또 존재하였고, 또 그 안에 다시 commentList가 존재하는, 뭔가 계속 서로를 호출하는 오류가 있다는 것을 알 수 있었다.
- 데이터베이스 상에 문제가 있는 것으로 보아 join하는 과정에서 문제가 있을 것이라고 추측하였다.
- 데이터베이스 매핑을 할때에 Entity에서 Cascade를 사용하면 되는 것으로 어렴풋이 기억을 하고 있는데 cascade를 어떻게 주어야하는지 몰라서 강의 교안을 살펴보았다.
- @OneToMany의 옵션 중에 cascade = 으로 cascade를 주는 옵션이 있어서 cascade = CASCADE.ALL 을 주어서 Type을 명시해서 주었다.
해결
- Cannot call sendError() after the response has been committed
- 서로를 계속 호출하고 있다는 것을 알고 상호 호출을 막을 수 있는 방법을 생각
- 데이터베이스 상에서 Post와 Comment가 일대다로 연결되어 있다는 것을 보고, 강의 교안 상에 존재하는 1대N 연결을 복습하였다.
- 하지만 큰 차이가 없었고 시도한지 1시간이 지나서 결국 검색을 해보게 되었다.
- Cannot call sendError() after the response has been committed라는 에러메시지가 의미하는 것은 '테이블과 테이블이 연관관계에 있으며 메서드를 통해서 데이터를 Front 쪽으로 보낼 때 Json으로 변환 도중에 무한으로 참조하는 오류' 라고 한다.
- 해결 방법은 해당 연관관계 매핑 부분에 @JsonIgnore를 붙이면 된다.
-> 해결
- 하지만 orphanRemoval=true이라는 옵션이 있고, 아니면 CascadeType.REMOVE로 CASCADE의 타입을 주는 옵션이 있는데 둘 중에 무엇을 사용해야 할 지 모르겠다.
- orphanRemoval=true vs CascadeType.REMOVE
- 검색해보니 둘 다 Parent가 삭제 되었을 때 Child도 함께 삭제시키는 역할을 수행하는 점에선 동일하나 "orphanRemoval=true는 관계가 끊어진 child를 자동으로 제거한다." 라고 한다.
-> 무슨 차이인지는 정확히 모르겠으나 orphanRemoval가 더 정확하게 제거하는 역할 인 것으로 보여 적용
-> 해결
알게 된 점 && 해야할 것
- Spring에서 서로를 무한 참조하는 오류가 발생해본 적은 없었고, 재귀 함수를 만들 때에나 있었던 오류였는데... @JsonIgnore라는 Annotation을 따로 만들어 둔 것으로 보니 실제 이런 에러가 자주 발생한다는 것으로 짐작을 할 수는 있으나, 데이터베이스를 제대로 만든다면 필요 없을 것이라는 생각이 든다.
- 제대로 데이터베이스 매핑 관계를 설정해서 해결하는 방법으로 시도해보아야겠다.
- CASCADE를 통해서 자동 삭제하는 기능을 적용해보았지만 아직도 데이터베이스 매핑에 관해서는 외워지지 않은 느낌이다. 또한 orphanRemoval와 CASCADE.REMOVE의 차이에 대해서도 조금 더 공부를 해야 할 것으로 보인다.