NewsFeed 프로젝트 : 친구 관리 기능 트러블 슈팅
친구 관리 기능 관련 ERD
- 역방향 친구 신청 등록을 방지하기 위해서 친구 요청을 보내게 되면 정방향으로 1번 역방향으로 1번 쿼리가 insert됨
- 1. 정방향 데이터 추가 : A가 B한테 친구신청을 보내서, from_id : a, to_id : b, is_friend : True를 insert
- 2. 역방향 데이터 추가 : from_id : b, to_id : a, is_friend : False를 insert
문제 : 의도하지 않은 inner join 수행 결과값
- 친구 신청한 목록을 조회하기 위해서 friend 테이블에 inner join을 수행했는데, 중복컬럼이 반복해서 나오게 됨
1번은 지금 2번과 3번에게 친구 신청을 보낸 상태
inner join을 사용하여 정방향 역방향을 합쳐서 데이터 조회를 수행함
select *
from friend f
inner join friend r
on f.from_id = r.to_id
하지만 조회 결과를 보니 중복된 컬럼이 나옴!!!
하지만 아무리 생각해도 f.from_id = r.to_id 이 조건이 전혀 틀린 것 같다는 생각이 들지 않았음
근데 더 고민을 해보니, 결국 inner join 이라 함은 자기 자신을 자기 자신과 조인하는 거기 때문에 역방향 기준도 생각을 해서 조인을 시켜줘햐 한다는 것을 깨달았다!
r.from_id = f.to_id 조건 추가!
select *
from friend f
inner join friend r
on f.from_id = r.to_id and r.from_id = f.to_id
중복없이 제대로 된 결과를 조회 할 수 있었다!
결론 : join 조건을 걸 때 inner join의 경우 한번 더 생각해서 조건을 걸어줘야 한다! 결국 friend 테이블에서는 from_id와 to_id는 같은 역할의 컬럼이기 때문에 당연히 동등하게 조건을 걸어 줘야 하는 것이다!!
문제 : 변경되지 않은 코드에서 갑자기 쿼리 수행이 제대로 되지 않음
친구 관련 기능을 모두 구현하고 이제 dev 브랜치에서 pull 을 받고 마저 테스트를 하는 중이었다..
그런데...!!!! 친구 관련 쪽 코드는 전혀 건들지 않았는데 갑자기 친구 수락 기능이 제대로 작동하지 않는 것이었다 ㅜㅜ
아무리 생각해도 변경된 코드도 없고 안될 이유가 없는데 너무 당황한 나머지 진짜 멘붕이 왔다...
첫번째 시도 : 스키마 자체를 날리고 다시 만들기
-> 스키마를 아예 삭제해버리고 application.properties의 속성도 변경해주고 친구 수락을 수행했다
spring.jpa.hibernate.ddl-auto=create
그러나 여전히 똑같은 실패 😵
두번째 시도 : 로그 찍기
아무래도 이쯤되니 쿼리가 문제인가 싶어서 로그를 찍어서 실제 값이 어떻게 넘어오는지 확인해보았다...
여기서는 friendReceivedtList 이게 분명히 조회가 잘 되는데!!!
그 결과 여기서는 리스트 안에 값이 정상적으로 담겨오고
여기서는 friendReceivedtList의 값이 빈값으로 나온다!!!!ㅜㅜㅜㅜㅜ
둘이 아예 똑같은 쿼리인데도 위에서는 잘 조회되고, 아래에서는 조회가 안되는 것이다....
기한이 하루 남았는데 갑자기 잘 되던 기능이 안되니까 정말 멘붕이 왔다!!!
세번째 시도 : 캐시 지우기
이쯤되니 정말 자포자기 하는 심정으로 구글링과 gpt한테 하소연을 했다...
이때 쿼리가 제대로 적용되지 않는 이유가 캐시 때문일 수도 있으니 캐시를 지우고 시도해보라는 답을 보게 되었다!!
@Service
public class FriendService {
@PersistenceContext
private EntityManager entityManager;
@Transactional
public void accept(FriendRequestAcceptDto acceptRequestDto, Long memberId) {
// 세션을 clear하여 캐시를 초기화
entityManager.clear();
// 이후 코드
List<Long> friendReceivedtList = friendRepository.getFriendReceivedList(memberId);
}
}
엔티티 매니저를 가지고 와서 캐시를 초기화해 줬더니 해결되었다!!!
Hibernate 1차 캐시
- Hibernate는 성능 최적화를 위해 1차 캐시 사용
- 세션 레벨에서 관리되는 캐시로, 같은 세션 내에서 동일한 엔티티가 여러 번 조회되면 DB에서 쿼리를 실행하지 않고 캐시된 데이터를 반환
- clear()를 호출하기 전에는, 데이터베이스에서 데이터를 가져와도 세션에 이미 캐시된 값이 존재하면 그것을 사용함
- 이로 인해 최근 변경된 데이터나 새로 조회된 데이터가 반영되지 않아서 조회가 제대로 되지 않았을 수 있음
캐시의 존재를 알고 있었지만 이렇게 내가 개발하면서 몸소 느끼게 될 줄은 몰랐다..😂
다음에 또 이런 오류가 생길 때 고생했던 만큼 금방 해결할 수 있을거라고 생각한다
결론 : 쿼리가 결과가 이상하게 나온다면 캐싱을 의심해 봐아 한다!
별첨 같은 느낌 ㅎㅎ ) 문제 : 인텔리제이 프로젝트 내부에 작업물이 보이지 않음
코드를 짜다가 렉이 좀 걸리는 것 같아서 인텔리제이를 종료하고 다시 실행했더니 프로젝트 내부에 내용물들이 하나도 보이지 않았다!!!!
구글링 결과 .idea를 지우고 재시작하면 된다고 했다!!
프로젝트 경로에서 아래 명령어를 수행하고 인텔리제이를 재시작하면 된다!!
ls -a
rm -rf .idea
에러는 사람을 정말 고통스럽게 하지만 고통스러운 만큼 많은걸 알게 해주는 것 같다...
고통받은만큼 성숙해지는 것 같다 ㅎㅎ (그래도 보고싶진 않아)