Spring

NewsFeed 프로젝트 : 친구 관리 기능 트러블 슈팅

김예나 2025. 2. 20. 03:58

친구 관리 기능 관련 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

 

 

에러는 사람을 정말 고통스럽게 하지만 고통스러운 만큼 많은걸 알게 해주는 것 같다...

고통받은만큼 성숙해지는 것 같다 ㅎㅎ (그래도 보고싶진 않아)