[삽질기] Argument Resolver와 영속성 컨텍스트

Oridev·2022년 6월 22일
1

JPA 삽질기

목록 보기
1/2

(오류 주의) 알고 있던 지식에 잘못된 부분이 있어 후속 글을 작성했습니다. 이 글을 참고해주세요!

안녕하세요. 오랜만에 글을 적어봅니다.
오늘 개발하며 있었던 소소한 삽질 또는 깨달음?을 공유해보려 가벼운 글을 적어봅니다.

🤔 상황 소개

현재 개발중인 어플리케이션에서 로그인 로직을 구현하고 있습니다. Interceptor를 활용하여 JWT 토큰을 검증하고, 유효한 토큰을 가지고 요청한 사용자라면 HttpServletRequest에 사용자 정보로 조회한 엔티티 객체인 User 객체를 보관하여 이후 요청에 활용하려는 상황입니다.

보통 userId만을 저장하기도 하지만, 그러면 User가 필요할 때마다 DB에 질의하여 가져와야 하기 때문에 이 방식이 굉장히 괜찮아보였습니다.

그리고 이 객체를 더 편리하게 사용하기 위해 ArgumentResolver를 도입했습니다.

ArgumentResolver란 쉽게 말하면, Controller로 들어오는 파라미터에 특정 어노테이션을 붙이거나 했을 때 그 argument를 가공해주는 역할을 합니다.

여기서는 HttpServeltRequest로부터 매번 getAttribute("user")를 하지 않기 위한 작업이라고 보시면 됩니다.
필요한 controller 메서드의 파라미터에 @Auth라는 어노테이션을 붙여서 User 객체를 추가하면 이 argument resolver가 작동하여 HttpServeltRequest로부터 user를 찾아 넣어줍니다.

😂 모든게 행복할 줄만 알았는데..

뭔가 우아(?)해 보이는 방법인 거 같아서 굉장히 맘에 들었습니다. 하지만 눈치 채신 분들도 있겠지만 문제가 발생합니다.

맨 처음 Interceptor를 보시면, AuthService로부터 객체를 조회하여 가져오게 됩니다.
이번 프로젝트에서는 JPA를 사용했습니다. 그렇기 때문에 Service 계층에서는 트랜잭션을 통해 가져온 객체가 반환되고 이를 HttpServeltRequest에 저장하였습니다.

문제는 JPA의 영속성 컨텍스트입니다. 영속성 컨텍스트는 한 마디로 DB와 어플리케이션의 중간 계층 쯤 되는 것으로, 트랜잭션이 진행되는 동안 DB로부터 가져온 엔티티나 어플리케이션에서 영속화한 엔티티에 대한 정보를 일시적으로 메모리에서 관리해주는 컨텍스트 정도로 이해하고 있습니다.

영속성 컨텍스트가 관리해주는 엔티티 객체는 트랜잭션이 끝나면 자동으로 변경 감지와 같은 것들이 일어나며 다시 DB로 커밋되게 됩니다.

문제는 AuthService로부터 유저를 가져오는 시점에 트랜잭션이 끝난다라는 점입니다. 이게 왜 문제일까요?

👀 바꿨는데요 안바뀌었습니다

문제를 발견한 건 로그아웃 기능을 만들 때였습니다. 사용자가 로그아웃을 하면 DB에 저장된 refresh token을 삭제하려고 했습니다. 그래서 api를 정의하고, controller에서는 argument resolver를 통해 로그아웃 할 user를 전달받고, service를 통해 user의 refresh token을 삭제한 후 별도의 쿼리를 날리지 않았습니다.

왜냐하면 당연히 영속성 컨텍스트가 변경 감지(더티 체킹)을 통해 저장해줄 것이라 기대했기 때문이었죠! 하지만 DB에는 아무 일도 일어나지 않았습니다. 왜냐하면 이미 이 user는 영속성 컨텍스트가 관리하는 객체가 아니었던 것입니다..

생각해보면 당연하다

왜 그럴까? 생각해보면 당연합니다. 이미 트랜잭션이 끝나고 커밋돼버린 user 객체는 더 이상 영속성 컨텍스트에서 관리하지도 않고 관리할 이유도 없습니다. 그걸 세션에서 꺼내서 재사용한다고 한들 영속성 컨텍스트와 이미 남남이 돼버린 객체는 수동으로 save를 호출하던지 해서 반영해야 했습니다.

또는 em.persist()를 통해 영속 상태로 만든 뒤에 user를 변경하고 트랜잭션을 종료하든 해야한다는 걸 깨달았습니다.

그러면서 근본적으로 'DB에 매번 조회하기 싫어서 HttpServeltRequestuser 객체를 넣었는데 영속성 컨텍스트에서 관리되지 않으니 어떻게 하는게 좋을까? 그냥 userId만 보관할까?' 라는 의문이 생겼습니다.

아직 이 질문에 대해 정답을 내리지 못해 주변 동료들에게도 의견을 물어보고 다른 코드를 참조해보기로 했습니다.

마치며

사소한 삽질이었지만 오랜만에 블로그에 글도 적을 겸 적어봤습니다! 너무 쉬운 주제여서 큰 도움이 안되셨다면 죄송합니다.

하지만 틈틈이 JPA 강의를 들으며 영속성 컨텍스트에 대해 배우고 있었는데 이런 주제를 마주쳐서 신기하기도 하고 정리해보고 싶어서 글을 적게 되었습니다!!

앞으로의 블로그는 이런 류의 삽질 공유나 하나의 주제를 정해 작성하는 것으로 활용해볼까 싶은 생각이 드네요!

읽어주셔서 감사합니다!! 🙇‍♂️

profile
천천히, 하지만 꾸준히 그리고 열심히

0개의 댓글