Search

68. 스프링부트 포토그램 좋아요 구현 무한참조 버그 잡기

좋아요 구현

무한참조 버그를 잡아보자..
전에도 계속 테스트하면서 무한참조때문에 갑자기 타임라인에 구독 이미지들이 안뜨는 현상이 있었는데
이번에 잡아본다
application.yml에서
update 부분을 create로 변경 후 저장 (그러면 테이블 날리고 다시 생성)
그리고 다시 update로 변경 후 저장
데이터가 지워졌다
근데 삭제가 안된 경우는
user
likes
subscribe
image
테이블이 서로 연관관계를 가지고 있는데
자식테이블부터 지워져야지 부모테이블이 지워진다.
(예를 들면 likes 테이블은 images랑 user 테이블이라 연관관계를 갖고있다)
(User 테이블을 참고해서 만들어진 Likes 테이블)
(Image 테이블을 참고해서 만들어진 Likes 테이블)
만약 User테이블을 먼저 지우면 Likes 테이블은 안지워진다. 그래서 자식들 먼저 지워줘야한다
DROP TABLE LIKES; DROP TABLE SUBSCRIBE; DROP TABLE IMAGES; DROP TABLE USER;
SQL
복사
이 순서대로 지우면 지워질거다.
이제 회원가입을 기존에 했던거 처럼
ssar
cos
love 순으로 가입
쌀이 사진 1개 올리고 cos,love 구독
cos가 사진 1개 올리고 ssar, love 구독
love는 그대로 둔다
다시 ssar 로 로그인해서 cos가 올린 사진 하나를 좋아요 눌러준다
이때 연속 새로고침해도 문제가 없다
postman에 가서
ssar로 로그인하고
{ "code": 1, "message": "성공", "data": { "content": [ { "id": 2, "caption": "cos가 올린 사진1", "postImageUrl": "7c604cb1-68ac-4f65-850b-cfa60f4508fc_스누피1.jpeg", "user": { "id": 2, "username": "cos", "password": "$2a$10$EqxZdF.Ydo0S08cMOnuOveLqS1oeXCqY2yjJd96dCqe1Zw/2X5E0e", "name": "코스", "website": null, "bio": null, "email": "cos@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "createDate": "2023-10-07T21:49:59.010141" }, "likes": [ { "id": 1, "user": { "id": 1, "username": "ssar", "password": "$2a$10$aF4k0ktQ6PzzZ7tXsUX53OO9AbVi9pbW2jHXGhjIeedunIABQNOmC", "name": "쌀", "website": null, "bio": null, "email": "ssar@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "images": [ { "id": 1, "caption": "쌀이 올린 사진 1", "postImageUrl": "98c3a57b-fd55-4ef4-ad14-485a7ed1e143_메타몽1.jpeg", "likes": [], "likeState": false, "likeCount": 0, "createDate": "2023-10-07T21:52:10.969586" } ], "createDate": "2023-10-07T21:49:52.961881" }, "createDate": "2023-10-07T21:54:46" } ], "likeState": true, "likeCount": 1, "createDate": "2023-10-07T21:54:36.94625" } ], "pageable": { "sort": { "sorted": false, "unsorted": true, "empty": true }, "pageNumber": 0, "pageSize": 3, "offset": 0, "paged": true, "unpaged": false }, "totalElements": 1, "totalPages": 1, "last": true, "numberOfElements": 1, "size": 3, "sort": { "sorted": false, "unsorted": true, "empty": true }, "first": true, "number": 0, "empty": false } }
JSON
복사
응답이 이렇게 온다
이미지를 들고 있는 user의 정보가 오고
likes에 대한 데이터가 온다
likes 데이터 안에는 user 정보가 있고 user 정보안에는 image 정보가 있다 또 image안에는 likes 정보가 있다…
images 안에 likes 값이 “likes” : []
이 값은 빈값인데 여기 안에 들오는 값은
쌀이 올린 이미지를 좋아요누른 사람들이 없기 때문이다.
근데 잘 보면
user 데이터만 있고 likes 테이블에 대한 데이터는 없다.
분면 둘다 넣어줬는데 말이다~
그 이유는
image에서 likes로 갈때 image는 json으로 파싱하지 말라고 적었기 때문이다
근데 user는 별도로 처리 안했기때문에 user 데이터는 나온다
user로 들어가보면
image가 또 있다
그래서 이렇게 보여지는거고
또 image 안에 들어가보면은
user랑 like가 나온다
근데 이미지 안에는 user는 없고 like만 있는데
user는 ignore 했기 때문이다
이 상태에서 누군가가 ssar이 올린 사진을 좋아요 하는 순간 무한참조 현상이 생긴다…!!!
cos로 로그인하고 ssar 이 올린 사진을 좋아요해준다
그리고 새로고침 하는순간
무한참조 오류가 난다..!!
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:472) ~[tomcat-embed-core-9.0.45.jar:9.0.45] at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129) ~[tomcat-servlet-api-9.0.43.jar:4.0.FR] at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129) ~[tomcat-servlet-api-9.0.43.jar:4.0.FR] at org.springframework.security.web.util.OnCommittedResponseWrapper.sendError(OnCommittedResponseWrapper.java:116) ~[spring-security-web-5.4.6.jar:5.4.6] at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129) ~[tomcat-servlet-api-9.0.43.jar:4.0.FR] at org.springframework.security.web.util.OnCommittedResponseWrapper.sendError(OnCommittedResponseWrapper.java:116) ~[spring-security-web-5.4.6.jar:5.4.6] at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.sendServerError(DefaultHandlerExceptionResolver.java:553) ~[spring-webmvc-5.3.6.jar:5.3.6] at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.handleHttpMessageNotWritable(DefaultHandlerExceptionResolver.java:443) ~[spring-webmvc-5.3.6.jar:5.3.6] at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.doResolveException(DefaultHandlerExceptionResolver.java:210) ~[spring-webmvc-5.3.6.jar:5.3.6] at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:141) ~[spring-webmvc-5.3.6.jar:5.3.6] at org.springframework.web.servlet.handler.HandlerExceptionResolverComposite.resolveException(HandlerExceptionResolverComposite.java:80) ~[spring-webmvc-5.
XML
복사
포스트맨에 cos로 로그인하고
아까와 같은 페이지를 호출하면 스크롤이 엄청 길게 생기면서 데이터가 깨졌다.
{ "code": 1, "message": "성공", "data": { "content": [ { "id": 1, "caption": "쌀이 올린 사진 1", "postImageUrl": "98c3a57b-fd55-4ef4-ad14-485a7ed1e143_메타몽1.jpeg", "user": { "id": 1, "username": "ssar", "password": "$2a$10$aF4k0ktQ6PzzZ7tXsUX53OO9AbVi9pbW2jHXGhjIeedunIABQNOmC", "name": "쌀", "website": null, "bio": null, "email": "ssar@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "createDate": "2023-10-07T21:49:52.961881" }, "likes": [ { "id": 2, "user": { "id": 2, "username": "cos", "password": "$2a$10$EqxZdF.Ydo0S08cMOnuOveLqS1oeXCqY2yjJd96dCqe1Zw/2X5E0e", "name": "코스", "website": null, "bio": null, "email": "cos@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "images": [ { "id": 2, "caption": "cos가 올린 사진1", "postImageUrl": "7c604cb1-68ac-4f65-850b-cfa60f4508fc_스누피1.jpeg", "likes": [ { "id": 1, "user": { "id": 1, "username": "ssar", "password": "$2a$10$aF4k0ktQ6PzzZ7tXsUX53OO9AbVi9pbW2jHXGhjIeedunIABQNOmC", "name": "쌀", "website": null, "bio": null, "email": "ssar@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "images": [ { "id": 1, "caption": "쌀이 올린 사진 1", "postImageUrl": "98c3a57b-fd55-4ef4-ad14-485a7ed1e143_메타몽1.jpeg", "likes": [ { "id": 2, "user": { "id": 2, "username": "cos", "password": "$2a$10$EqxZdF.Ydo0S08cMOnuOveLqS1oeXCqY2yjJd96dCqe1Zw/2X5E0e", "name": "코스", "website": null, "bio": null, "email": "cos@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "images": [ { "id": 2, "caption": "cos가 올린 사진1", "postImageUrl": "7c604cb1-68ac-4f65-850b-cfa60f4508fc_스누피1.jpeg", "likes": [ { "id": 1, "user": { "id": 1, "username": "ssar", "password": "$2a$10$aF4k0ktQ6PzzZ7tXsUX53OO9AbVi9pbW2jHXGhjIeedunIABQNOmC", "name": "쌀", "website": null, "bio": null, "email": "ssar@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "images": [ { "id": 1, "caption": "쌀이 올린 사진 1", "postImageUrl": "98c3a57b-fd55-4ef4-ad14-485a7ed1e143_메타몽1.jpeg", "likes": [ { "id": 2, "user": { "id": 2, "username": "cos", "password": "$2a$10$EqxZdF.Ydo0S08cMOnuOveLqS1oeXCqY2yjJd96dCqe1Zw/2X5E0e", "name": "코스", "website": null, "bio": null, "email": "cos@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "images": [ { "id": 2, "caption": "cos가 올린 사진1", "postImageUrl": "7c604cb1-68ac-4f65-850b-cfa60f4508fc_스누피1.jpeg", "likes": [ { "id": 1, "user": { "id": 1, "username": "ssar", "password": "$2a$10$aF4k0ktQ6PzzZ7tXsUX53OO9AbVi9pbW2jHXGhjIeedunIABQNOmC", "name": "쌀", "website": null, "bio": null, "email": "ssar@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "images": [ { "id": 1, "caption": "쌀이 올린 사진 1", "postImageUrl": "98c3a57b-fd55-4ef4-ad14-485a7ed1e143_메타몽1.jpeg", "likes": [ { "id": 2, "user": { "id": 2, "username": "cos", "password": "$2a$10$EqxZdF.Ydo0S08cMOnuOveLqS1oeXCqY2yjJd96dCqe1Zw/2X5E0e", "name": "코스", "website": null, "bio": null, "email": "cos@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "images": [ { "id": 2, "caption": "cos가 올린 사진1", "postImageUrl": "7c604cb1-68ac-4f65-850b-cfa60f4508fc_스누피1.jpeg", "likes": [ { "id": 1, "user": { "id": 1, "username": "ssar", "password": "$2a$10$aF4k0ktQ6PzzZ7tXsUX53OO9AbVi9pbW2jHXGhjIeedunIABQNOmC", "name": "쌀", "website": null, "bio": null, "email": "ssar@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "images": [ { "id": 1, "caption": "쌀이 올린 사진 1", "postImageUrl": "98c3a57b-fd55-4ef4-ad14-485a7ed1e143_메타몽1.jpeg", "likes": [ { "id": 2, "user": { "id": 2, "username": "cos", "password": "$2a$10$EqxZdF.Ydo0S08cMOnuOveLqS1oeXCqY2yjJd96dCqe1Zw/2X5E0e", "name": "코스",
JSON
복사
보면은 초반에 user까진 문제가없고
likes안에 user안에 images안(여기서부터 문제)에 likes 안에 user 안에 … . 무한 참조가 시작된다
Likes.java에서 오류가 터지면 잡자고 했던 부분이 있다 ㅋㅋ 여기에
@JsonIgnoreProperties({"images"}) @JoinColumn(name="userId") @ManyToOne private User user; // 1
Java
복사
포스트맨에서 다시 보내면
{ "code": 1, "message": "성공", "data": { "content": [ { "id": 1, "caption": "쌀이 올린 사진 1", "postImageUrl": "98c3a57b-fd55-4ef4-ad14-485a7ed1e143_메타몽1.jpeg", "user": { "id": 1, "username": "ssar", "password": "$2a$10$aF4k0ktQ6PzzZ7tXsUX53OO9AbVi9pbW2jHXGhjIeedunIABQNOmC", "name": "쌀", "website": null, "bio": null, "email": "ssar@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "createDate": "2023-10-07T21:49:52.961881" }, "likes": [ { "id": 2, "user": { "id": 2, "username": "cos", "password": "$2a$10$EqxZdF.Ydo0S08cMOnuOveLqS1oeXCqY2yjJd96dCqe1Zw/2X5E0e", "name": "코스", "website": null, "bio": null, "email": "cos@nate.com", "phone": null, "gender": null, "profileImageUrl": null, "role": "ROLE_USER", "createDate": "2023-10-07T21:49:59.010141" }, "createDate": "2023-10-07T22:14:36" } ], "likeState": true, "likeCount": 1, "createDate": "2023-10-07T21:52:10.969586" } ], "pageable": { "sort": { "sorted": false, "unsorted": true, "empty": true }, "pageNumber": 0, "pageSize": 3, "offset": 0, "paged": true, "unpaged": false }, "totalElements": 1, "totalPages": 1, "last": true, "numberOfElements": 1, "size": 3, "sort": { "sorted": false, "unsorted": true, "empty": true }, "first": true, "number": 0, "empty": false } }
Java
복사
무한참조 없이 잘 데이터가 넘어온다!!!
이제 속 시원 ㅎㅎ

*참고