could not initialize proxy - no Session
문제 발생 상황
회원탈퇴 기능 구현 중에 발생했는데, Controller 클래스에서 현재 이용중인 유저 정보를 알기 위해서 항상 파라미터로 @AuthenticationPrincipal PrincipalDetails principalDetails
을 추가해왔다.
그렇게 유저 정보가 필요하면 principalDetails.getUser()
를 써왔는데, 회원탈퇴 버튼을 눌렀을 때 Controller에 Delete request가 들어오면 매핑돼 있는 함수가 실행되면서 현재 유저를 principalDetails.getUser()
로
받고 해당 유저에 @OneToMany로 연관돼있는 posts
나 notifications
를 가져와야 했는데, 다 지연 로딩으로 설정돼 있다보니 실제 값이 넘어오질 않고 proxy만 있어서 에러가 발생했다.
당시에 아예 모든 관계를 지연 로딩으로 설정해준 뒤였기 때문에(사실 @OneToMany는 기본값이 지연로딩이지만) fetch join이 걸리지 않은게 있는지 열심히 찾아봤었던 기억이 난다.
현재 유저의 id 값만 받아와 UserRepository.findOneById()
로 유저 정보를 가져오면 되지 않을까 싶어 시도 해봤지만 해결되지 않았다.
could not initialize proxy - no Session
해결
왜 no Session 에러가 뜨는걸까? 회원탈퇴처럼 회원 탈퇴 이전에 연관된 모든 정보를 지우는 작업(즉, 수정하는 작업)을 할 때는 반드시 영속성 컨텍스트 내부에서 진행해야 한다.
Controller에서 어떤 유저에 대해 정보를 수정하는 작업을 하는 경우 해당 유저는 더 이상 영속성 컨텍스트 내에서 관리되지 않기 때문에 준영속 상태다.
수정 작업이 진행되는 Service 클래스 내 함수들은 모두 @Transactional
을 설정해 두었는데, 해당 함수 내에서 어떤 entity의 값을 수정할 경우 굳이 DB로 직접 쿼리를 날리지 않아도
변경 감지를 통해 알아서 업데이트 쿼리를 날려주는걸 경험해봤을 것이다. 그 이유가 영속성 컨텍스트 내에서 관리되는, 영속 상태인 entity에 대해서 값을 수정했기 때문이다.
즉, @Transactional
이 붙어있는 함수는 호출된 시점부터 끝날 때 까지의 내용이 모두 transaction 내부에서 처리되는 작업으로 간주한다.
그러니까 Controller 내에서 변경 작업이 필요한 내용들을 처리하지 말고, Service의 @Transactioal
이 붙은 함수 내에서 처리해주면 해결된다.
댓글남기기